/*
 * Copyright (c) 1999 - 2001, Artur Merke <amerke@ira.uka.de> 
 *
 * This file is part of FrameView2d.
 *
 * FrameView2d is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * FrameView2d is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with FrameView2d; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include "smonitor_dev.h"
#include "global_defs.h"

#include <iostream>
//#include <strstream>
//#include <sstream>

#include <iomanip>
#include <stdio.h>			/* Standard I/O definitions. */
#include <cstdlib>			/* Standard C Library definitions. */
#include <cstring>			/* C Library string functions. */
#include <ctype.h>  /* isprint(...) */

#include <netinet/in.h> /* wegen htons(...)*/
#include <math.h>

//#include "object2d.h"
#include "rgb_db.h"
#include "ascii_processor.h"
#include "str2val.h"
//#include "tools.h"

//#define DEBUG(XXX) cout << "\ndebug(" << __LINE__ << "):" XXX << flush
#define DEBUG(XXX)

//#define WEBFIELD 1 //just a macro which doesn't show the menu and the players (for the NetPlayer)
/*****************************************************************************
 \short soccerserver parameters (version 1 and 2)

 This part contains server specific data types, which are taken from the files
   - sserver-6.XX/server/param.h
   - sserver-6.XX/server/utility
 and for the extension for protocol version 2
   - sserver-7.00/server/param.h
   - sserver-7.00/server/utility
*/
namespace SSrv {
// from  utility.h
#define PI M_PI

// from param.h

#define SHOWINFO_SCALE          16.0
#define SHOWINFO_SCALE2         65536.0 //ver. 2
#define SHOWINFO_SCALE2_int     65536   //art!

#define NO_INFO         0  //ver. 2
#define SHOW_MODE       1
#define MSG_MODE        2
#define DRAW_MODE       3
#define BLANK_MODE      4
#define PM_MODE         5  //ver. 2
#define TEAM_MODE       6  //ver. 2
#define PT_MODE         7  //ver. 2
#define PARAM_MODE      8  //ver. 2
#define PPARAM_MODE     9  //ver. 2
#define FRAMEVIEW_MODE  10 //art!!!

#define DrawClear       0
#define DrawPoint       1
#define DrawCircle      2
#define DrawLine        3
#define MSG_BOARD       1
#define LOG_BOARD       2

//#define MAX_PLAYER 11

#define	DISABLE			0x0000
#define	STAND			0x0001
#define	KICK			0x0002
#define KICK_FAULT		0x0004
#define	GOALIE			0x0008
#define CATCH			0x0010
#define CATCH_FAULT		0x0020
#define BALL_TO_PLAYER          0x0040
#define PLAYER_TO_BAL           0x0080
#define DISCARD                 0x0100
#define BALL_COLLIDE            0x0400 // player collided with the ball
#define PLAYER_COLLIDE          0x0800 // player collided with another player

#define PLAYMODE_STRINGS {"",\
                        "before_kick_off",\
                        "time_over",\
                        "play_on",\
                        "kick_off_l",\
                        "kick_off_r",\
                        "kick_in_l",\
                        "kick_in_r",\
                        "free_kick_l",\
                        "free_kick_r",\
                        "corner_kick_l",\
                        "corner_kick_r",\
                        "goal_kick_l",\
                        "goal_kick_r",\
                        "goal_l",\
                        "goal_r",\
                        "drop_ball",\
                        "offside_l",\
                        "offside_r",\
                        "penalty_kick_l",\
                        "penalty_kick_r",\
                        "first_half_over",\
                        "pause",\
                        "human_judge",\
                        "foul_charge_l",\
                        "foul_charge_r",\
                        "foul_push_l",\
                        "foul_push_r",\
                        "foul_multiple_attack_l",\
                        "foul_multiple_attack_r",\
                        "foul_ballout_l",\
                        "foul_ballout_r",\
                        "back_pass_l", \
                        "back_pass_r", \
                        "free_kick_fault_l", \
                        "free_kick_fault_r" \
                }

#define	COLOR_NAME_MAX	64

typedef struct {
	short	enable ;
	short	side ;
	short	unum ;
	short	angle ;
	short	x ;
	short	y ;
} pos_t ;

typedef struct {
	char	name[16] ;
	short	score ;
} team_t ;

typedef struct {
	char	pmode ;
	team_t	team[2] ;
	pos_t	pos[MAX_PLAYER * 2 + 1] ;
	short	time ;
} showinfo_t ;

typedef	struct {
	short	board ;
	char	message[2048] ;
} msginfo_t ;

typedef struct {
	short	x ;
	short	y ;
	char	color[COLOR_NAME_MAX] ;
} pointinfo_t ;

typedef struct {
	short	x ;
	short	y ;
	short	r ;
	char	color[COLOR_NAME_MAX] ;
} circleinfo_t ;
	
typedef struct {
	short	x1 ;
	short	y1 ;
	short	x2 ;
	short	y2 ;
	char	color[COLOR_NAME_MAX] ;
} lineinfo_t ;

typedef struct {
	short mode ;
	union {
		pointinfo_t		pinfo ;
		circleinfo_t	cinfo ;
		lineinfo_t		linfo ;
	} object ;
} drawinfo_t ;

typedef struct {
	short	mode ;
	union {
		showinfo_t	show ;
		msginfo_t	msg ;
		drawinfo_t	draw ;
	} body ;
} dispinfo_t ;


typedef struct {
  long x;
  long y;
  long deltax;
  long deltay;
} ball_t;

typedef struct {
  short mode;
  short type;
  long x;
  long y;
  long deltax;
  long deltay;
  long body_angle;
  long head_angle;
  long view_width;
  short view_quality;
  long stamina;
  long effort;
  long recovery;
  short kick_count;
  short dash_count;
  short turn_count;
  short say_count;
  short tneck_count;
  short catch_count;
  short move_count;
  short chg_view_count;
} player_t;

typedef struct {
  char          pmode ;
  team_t        team[2] ;
  ball_t        ball;
  player_t      pos[MAX_PLAYER * 2] ;
  short         time ;
} showinfo_t2 ;  

typedef struct {
    short id;
    long player_speed_max;
    long stamina_inc_max;
    long player_decay;
    long inertia_moment;
    long dash_power_rate;
    long player_size;
    long kickable_margin;
    long kick_rand;
    long extra_stamina;
    long effort_max;
    long effort_min;

  // spare variables which are to be used for paramenter added in the future    
    long sparelong1;
    long sparelong2;
    long sparelong3;
    long sparelong4;
    long sparelong5;
    long sparelong6;
    long sparelong7;
    long sparelong8;
    long sparelong9;
    long sparelong10;
} player_type_t;

typedef struct
{
    long gwidth ;					/* goal width */
    long inertia_moment ;			/* intertia moment for turn */
    long psize ;					/* player size */
    long pdecay ;					/* player decay */
    long prand ;					/* player rand */
    long pweight ;					/* player weight */
    long pspeed_max ;				/* player speed max */
    // th 6.3.00
    long paccel_max ;				/* player acceleration max */
    //
    long stamina_max ;				/* player stamina max */
    long stamina_inc ;				/* player stamina inc */
    long recover_init ;			/* player recovery init */
    long recover_dthr ;			/* player recovery decriment threshold */
    long recover_min ;				/* player recovery min */
    long recover_dec ;				/* player recovery decriment */
    long effort_init ;				/* player dash effort init */
    long effort_dthr ;				/* player dash effort decriment threshold */
    long effort_min ;				/* player dash effrot min */
    long effort_dec ;				/* player dash effort decriment */
    long effort_ithr ;				/* player dash effort incriment threshold */
    long effort_inc ;				/* player dash effort incriment */
    // pfr 8/14/00: for RC2000 evaluation
    long kick_rand;                                /* noise added directly to kicks */
    short team_actuator_noise;                        /* flag whether to use team specific actuator noise */
    long prand_factor_l;                           /* factor to multiple prand for left team */
    long prand_factor_r;                           /* factor to multiple prand for right team */
    long kick_rand_factor_l;                       /* factor to multiple kick_rand for left team */
    long kick_rand_factor_r;                       /* factor to multiple kick_rand for right team */

    long bsize ;					/* ball size */
    long bdecay ;					/* ball decay */
    long brand ;					/* ball rand */
    long bweight ;					/* ball weight */
    long bspeed_max ;				/* ball speed max */
    // th 6.3.00
    long baccel_max;				/* ball acceleration max */
    //
    long dprate ;					/* dash power rate */
    long kprate ;					/* kick power rate */
    long kmargin ;					/* kickable margin */
    long ctlradius ;				/* control radius */
    long ctlradius_width ;			/* (control radius) - (plyaer size) */
    long maxp ;					/* max power */
    long minp ;					/* min power */
    long maxm ;					/* max moment */
    long minm ;					/* min moment */
    long maxnm ;					/* max neck moment */
    long minnm ;					/* min neck moment */
    long maxn ;					/* max neck angle */
    long minn ;					/* min neck angle */
    long visangle ;				/* visible angle */
    long visdist ;					/* visible distance */
    long windir ;					/* wind direction */
    long winforce ;				/* wind force */
    long winang ;					/* wind angle for rand */
    long winrand ;					/* wind force for force */
    long kickable_area ;			/* kickable_area */
    long catch_area_l ;			/* goalie catchable area length */
    long catch_area_w ;			/* goalie catchable area width */
    long catch_prob ;				/* goalie catchable possibility */
    short   goalie_max_moves;                 /* goalie max moves after a catch */	
    long ckmargin ;				/* corner kick margin */
    long offside_area ;			/* offside active area size */
    short win_no ;					/* wind factor is none */
    short win_random ;				/* wind factor is random */
    short say_cnt_max ;				/* max count of coach SAY */
    short SayCoachMsgSize ;				/* max length of coach SAY */
    short clang_win_size;
    short clang_define_win;
    short clang_meta_win;
    short clang_advice_win;
    short clang_info_win;
    short clang_mess_delay;
    short clang_mess_per_cycle;
    short half_time ;					/* half time */
    short sim_st ;					/* simulator step interval msec */
    short send_st ;					/* udp send step interval msec */
    short recv_st ;					/* udp recv step interval msec */
    short sb_step ;					/* sense_body interval step msec */
    short lcm_st ;		                        /* lcm of all the above steps msec */
    short SayMsgSize ;				/* string size of say message */
    short hear_max ;					/* player hear_capacity_max */
    short hear_inc ;					/* player hear_capacity_inc */
    short hear_decay ;				/* player hear_capacity_decay */
    short cban_cycle ;				/* goalie catch ban cycle */
    short slow_down_factor ;                          /* factor to slow down simulator and send intervals */
    short useoffside ;				/* flag for using off side rule */
    short kickoffoffside ;			/* flag for permit kick off offside */
    long offside_kick_margin ;		/* offside kick margin */
    long audio_dist ;				/* audio cut off distance */
    long dist_qstep ;				/* quantize step of distance */
    long land_qstep ;				/* quantize step of distance for landmark */
    long dir_qstep ;				/* quantize step of direction */
    long dist_qstep_l ;			/* team right quantize step of distance */
    long dist_qstep_r ;			/* team left quantize step of distance */
    long land_qstep_l ;			/* team right quantize step of distance for landmark */
    long land_qstep_r ;			/* team left quantize step of distance for landmark */
    long dir_qstep_l ;				/* team left quantize step of direction */
    long dir_qstep_r ;				/* team right quantize step of direction */
    short CoachMode ;				/* coach mode */
    short CwRMode ;					/* coach with referee mode */
    short old_hear ;					/* old format for hear command (coach) */
    short sv_st ;					/* online coach's look interval step */


  // spare variables which are to be used for paramenter added in the future
  long sparelong1;
  long sparelong2;
  long sparelong3;
  long sparelong4;
  long sparelong5;
  long sparelong6;
  long sparelong7;
  long sparelong8;
  long sparelong9;
  long sparelong10;

  short spareshort1;
  short spareshort2;
  short spareshort3;
  short spareshort4;
  short spareshort5;
  short spareshort6;
  short spareshort7;
  short spareshort8;
  short spareshort9;
  short spareshort10;
  
} server_params_t;

typedef struct {
    short player_types;
    short subs_max;
    short pt_max;
    
    long player_speed_max_delta_min;
    long player_speed_max_delta_max;
    long stamina_inc_max_delta_factor;
    
    long player_decay_delta_min;
    long player_decay_delta_max;
    long inertia_moment_delta_factor;

    long dash_power_rate_delta_min;
    long dash_power_rate_delta_max;
    long player_size_delta_factor;

    long kickable_margin_delta_min;
    long kickable_margin_delta_max;
    long kick_rand_delta_factor;

    long extra_stamina_delta_min;
    long extra_stamina_delta_max;
    long effort_max_delta_factor;
    long effort_min_delta_factor;

    long sparelong1;
    long sparelong2;
    long sparelong3;
    long sparelong4;
    long sparelong5;
    long sparelong6;
    long sparelong7;
    long sparelong8;
    long sparelong9;
    long sparelong10;

  short spareshort1;
  short spareshort2;
  short spareshort3;
  short spareshort4;
  short spareshort5;
  short spareshort6;
  short spareshort7;
  short spareshort8;
  short spareshort9;
  short spareshort10;

} player_params_t;

typedef struct {
  short mode;
  union {
      showinfo_t2 		show;
      msginfo_t 		msg;
      player_type_t		ptinfo;
      server_params_t		sparams;
      player_params_t		pparams;
  } body;
} dispinfo_t2 ;

}

/******************************************************************************/

ostream & operator<< (ostream & o, const RGBcolor & col) {
  const char numbers[16]= {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
  o << numbers[col.red/16] << numbers[col.red%16]
    << numbers[col.green/16] <<numbers[ col.green%16]
    << numbers[col.blue/16] << numbers[col.blue%16];
  return o;
}

class PlayerTypes {
  struct _player_type {
    _player_type() { valid= false; }
    bool valid;
    double player_radius;
    double kickable_margin;
  };
  static double ball_radius;
  static const int NUM_TYPES= 7;
  static _player_type std_type;
  static _player_type types[NUM_TYPES];
public:
  static bool use_std_type;

  static void init(double std_ball_radius, double std_player_radius, double std_kickable_margin) {
    ball_radius= std_ball_radius;
    std_type.valid= true;
    std_type.player_radius= std_player_radius;
    std_type.kickable_margin= std_kickable_margin;
    use_std_type= true;
  }
  
  static void set_type(int type, double player_radius, double kickable_margin) {
    if (type < 0 || type >= NUM_TYPES) {
      WARNING_OUT << "\nwrong player type number" << type << " (ignoring)";
      return;
    }
    types[type].valid= true;
    types[type].player_radius= player_radius;
    types[type].kickable_margin= kickable_margin;
  }

  static double get_player_radius(int type) {
    if (type == -1 || use_std_type) // default type
      return std_type.player_radius;

    if (type < 0 || type >= NUM_TYPES) {
      WARNING_OUT << "\nwrong player type number" << type << " (using std type)";
      return std_type.player_radius;
    }

    if ( !types[ type ].valid ) {
      WARNING_OUT << "\nplayer type " << type << " not valid (using std type)";
      return std_type.player_radius;
    }

    return types[type].player_radius;
  }

  static double get_kick_radius(int type) {
    double def_result= std_type.player_radius + std_type.kickable_margin + ball_radius;

    if (type == -1 || use_std_type) // default type
      return def_result;

    if (type < 0 || type >= NUM_TYPES) {
      WARNING_OUT << "\nwrong player type number" << type << " (using std type)";
      return def_result;
    }
    if ( !types[ type ].valid ) {
      WARNING_OUT << "\nplayer type " << type << " not valid (using std type)";
      return def_result;
    }
    return types[type].player_radius + types[type].kickable_margin + ball_radius;
  }
};

//definition of the static internal data of PlayerTypes
double PlayerTypes::ball_radius;
PlayerTypes::_player_type PlayerTypes::std_type;
PlayerTypes::_player_type PlayerTypes::types[PlayerTypes::NUM_TYPES];
bool PlayerTypes::use_std_type;

/******************************************************************************/

VisualPlayersViewArea::VisualPlayersViewArea() {
}

void VisualPlayersViewArea::init(int my_key, int my_layer, const RGBcolor & my_exact, const RGBcolor & my_fuzzy) {
  key= my_key;
  layer= my_layer;
  c_fuzzy= my_fuzzy;
  c_exact= my_exact;
  circlearc1.set_color(c_fuzzy);
  circlearc1.filled= true;

  circle.set_color(c_fuzzy);
  circle.filled= true;
  circle.rel.radius= 3.0; //feel range

  circlearc2.set_color(c_exact);
  circlearc2.filled= true;

  view_quality= -1;
  view_width= -1.0;
  set_view_mode(FEEL_RANGE,0.5*M_PI);
}

void VisualPlayersViewArea::draw(DisplayBase * disp, const Area2d & area, const Frame2d & p_frame, bool chg) {
  circlearc1.draw(disp,area,p_frame,chg);
  circle.draw(disp,area,p_frame,chg);
  circlearc2.draw(disp,area,p_frame,chg);
}
void VisualPlayersViewArea::actualize(const Frame2d& f, bool chg) {
  circlearc1.actualize(f,chg);
  circle.actualize(f,chg);
  circlearc2.actualize(f,chg);
}
void VisualPlayersViewArea::set_view_mode( int quality, double width ) {
  if (quality != view_quality) {
    view_quality= quality;
    switch (view_quality) {
    case LOW:
      circlearc1.rel.radius= 40;
      circlearc1.changed= true;
      circlearc1.visible= true;

      circlearc2.rel.radius= 20;
      circlearc2.changed= true;
      circlearc2.visible= false;
      break;
    case HIGH:
      circlearc1.rel.radius= 60;
      circlearc1.changed= true;
      circlearc1.visible= true;

      circlearc2.rel.radius= 40;
      circlearc2.changed= true;
      circlearc2.visible= true;
      break;
    case FEEL_RANGE:
      circlearc1.visible= false;
      circlearc2.visible= false;
      break;
    default:
      ERROR_OUT << "wrong view_quality " << view_width;
    }
  }

  if ( fabs(width - view_width) > 0.01 ) {
    view_width= width;
    Angle a= 0.5* view_width;
    circlearc1.rel.ang1= -a;
    circlearc1.rel.ang2=  a;
    circlearc1.changed= true;

    circlearc2.rel.ang1= -a;
    circlearc2.rel.ang2=  a;
    circlearc2.changed= true;
  }
}

/******************************************************************************/

VisualBall::VisualBall() {

}

void VisualBall::init(int my_key, int my_layer, double my_small_r, double my_large_r,
		      const RGBcolor & my_c_ball,
		      const RGBcolor & my_c_line_until_ball_stops,
		      const RGBcolor & my_c_line_markers,
		      const RGBcolor & my_c_font) {
  ball_decay= 0.94;
  key= my_key;
  layer= my_layer;

  c_ball= my_c_ball;
  c_line_until_ball_stops= my_c_line_until_ball_stops;
  c_line_markers= my_c_line_markers;
  c_font= my_c_font;

  show_vel= false;
  show_vel_string= false;
  changed= true;

  double small_r= my_small_r;
  double large_r= my_large_r;
  
  ball_point.use_intersects_area= false;
  ball_point.set_color(c_ball);

  ball_circle.rel.radius= small_r;
  ball_circle.use_intersects_area= false;
  ball_circle.set_color(c_ball);
  ball_circle.filled= true;

  ball_margin.rel.radius= large_r;
  ball_margin.use_intersects_area= false;
  ball_margin.set_color(c_ball);
  ball_margin.filled= false;

  line_until_ball_stops.use_intersects_area= false;
  line_until_ball_stops.set_color(c_line_until_ball_stops);

  line_markers.set_max_size(MAX_LINE_MARKERS_NUM);
  line_markers.set_cur_size(0);
  line_markers.use_intersects_area= false;
  line_markers.set_color(c_line_markers);

  label.content.set_max_size(MAX_LABEL_LEN);
  label.content.set_cur_size(0);
  //label.content.tab[0]= 'b';
  label.set_color(c_font);
}

void VisualBall::draw(DisplayBase * disp, const Area2d & area, const Frame2d & p_frame, bool chg) {
  changed= changed || chg;

  ball_point.actualize(p_frame,changed);
  if ( ! ball_point.intersects_area(area) )
    return;

  if ( show_vel ) {
    line_until_ball_stops.draw(disp,area,p_frame,changed);
    line_markers.draw(disp,area,p_frame * vel_frame, changed);
  }

  ball_point.draw(disp,area,p_frame,false); //already actualized!

  ball_circle.draw(disp,area,p_frame,changed);
  ball_margin.draw(disp,area,p_frame,changed);

  if ( show_vel_string ) {
    label.draw(disp,area,p_frame,changed);
  }

  changed= false;
}

void VisualBall::actualize(const Frame2d& f, bool chg) {
  changed= changed || chg;

  ball_point.actualize(f,changed);
  ball_circle.actualize(f,changed);
  ball_margin.actualize(f,changed);

  line_until_ball_stops.actualize(f,changed);
  line_markers.actualize(f,changed);

  label.actualize(f,changed);

  changed= false;
}

void VisualBall::set_show_vel( const Point2d & vel_as_point ) {
  show_vel= true;

  Vector2d vel= Vector2d(vel_as_point.x, vel_as_point.y);
  double norm= vel.norm();

  line_until_ball_stops.rel.p2.x=  vel.x / ( 1.0 - ball_decay);
  line_until_ball_stops.rel.p2.y=  vel.y / ( 1.0 - ball_decay);
  line_until_ball_stops.changed= true;

  vel_frame.set_angle( vel );

  line_markers.changed= true;
  if ( norm < 0.5 ) {
    line_markers.set_cur_size(0);
    return;
  }

  double distance= 0.0;
  line_markers.set_cur_size(MAX_LINE_MARKERS_NUM);
  for (int i=0; i< MAX_LINE_MARKERS_NUM; i++) {
    distance += norm;
    line_markers.rel.tab[i].p1.x= distance;
    line_markers.rel.tab[i].p1.y= -0.5*norm;
    line_markers.rel.tab[i].p2.x= distance;
    line_markers.rel.tab[i].p2.y=  0.5*norm;

    norm *= ball_decay;
    if ( norm < 0.5 ) {
      line_markers.set_cur_size(i+1);
      break;
    }
  }
}

void VisualBall::set_show_vel_string( const Point2d & vel ) {
  //sprintf( label.content.tab,"(%.2lf,%.2lf)  ", vel.x, vel.y);
  show_vel_string= true;
  sprintf( label.content.tab,"(%.2f,%.2f)", vel.x, vel.y);
  label.content.cur_size= strlen(label.content.tab);
  label.changed= true;
  //cout << "\nlabel= " << label.content.tab << flush;
}

/******************************************************************************/

VisualPlayer::VisualPlayer() { 
}

void VisualPlayer::init(int my_key, int my_layer, char p_char,
			const RGBcolor & my_c_invalid,
			const RGBcolor & my_c_player,
			const RGBcolor & my_c_goalie,
			const RGBcolor & my_c_font) {
  key= my_key;
  layer= my_layer;

  c_invalid= my_c_invalid;
  c_player= my_c_player;
  c_goalie= my_c_goalie;
  c_font= my_c_font;
  c_black= RGBcolor(0,0,0);
  c_white= RGBcolor(255,255,255);
  c_red=   RGBcolor(255,0,0);

  type= -1;
  use_number= true;
  show_kick= false;
  ball_collision= false;
  is_active= false;
  is_goalie= false;
  changed= true;

  double small_r= PlayerTypes::get_player_radius(type);
  double large_r= PlayerTypes::get_kick_radius(type);
  
  body_bg.rel.radius= large_r;
  body_bg.use_intersects_area= false;
  body_bg.set_color(c_invalid);
  body_bg.filled= true;

  body.rel.radius= small_r;
  body.use_intersects_area= false;
  body.set_color(c_black);

  body_margin.rel.radius= large_r;
  body_margin.use_intersects_area= false;
  body_margin.set_color(c_black);

  body_margin_kick.rel.radius= large_r;
  body_margin_kick.use_intersects_area= false;
  body_margin_kick.set_color(c_white);

  body_margin_ball_collision.rel.radius= large_r;
  body_margin_ball_collision.use_intersects_area= false;
  body_margin_ball_collision.filled= true;
  body_margin_ball_collision.set_color(c_red);

  body_dir.rel.p2.x= large_r;
  body_dir.use_intersects_area= false;
  body_dir.set_color(c_black);

  head_dir.rel.p2.x= large_r;
  head_dir.use_intersects_area= false;
  head_dir.set_color(c_red);

  label.content.set_max_size(MAX_LABEL_LEN);
  label.content.set_cur_size(1);
  label.content.tab[0]= p_char;
  label.set_color(c_font);
}

void VisualPlayer::draw(DisplayBase * disp, const Area2d & area, const Frame2d & p_frame, bool chg) {
  changed= changed || chg;

  body_bg.actualize(p_frame,changed);
  if ( ! body_bg.intersects_area(area) )
    return;

  body_bg.draw(disp,area,p_frame,false); //already actualized!

  if (ball_collision)
    body_margin_ball_collision.draw(disp,area,p_frame,changed);

  body.draw(disp,area,p_frame,changed);

  if (show_kick) 
    body_margin_kick.draw(disp,area,p_frame,changed);
  else
    body_margin.draw(disp,area,p_frame,changed);

  body_dir.draw(disp,area,p_frame,changed);

  head_dir.draw(disp,area,p_frame * head_frame, changed || head_frame_chg);
  head_frame_chg= false;

  if (use_number)
    label.draw(disp,area,p_frame,changed);

  changed= false;
}

void VisualPlayer::actualize(const Frame2d& f, bool chg) {
  changed= changed || chg;

  body_bg.actualize(f,changed);
  body.actualize(f,changed);
  body_margin.actualize(f,changed);
  
  body_dir.actualize(f,changed);

  head_dir.actualize(f * head_frame, changed || head_frame_chg); //must be changed
  head_frame_chg= false;

  label.actualize(f,changed);

  changed= false;
}

void VisualPlayer::set_type(int t) {
  if ( type == t)
    return;

  //cout << "\n type " << type << "->" << t;

  type= t;
  
  double small_r= PlayerTypes::get_player_radius(type);
  double large_r= PlayerTypes::get_kick_radius(type);
  
  body_bg.rel.radius= large_r;
  body_bg.changed= true;

  body.rel.radius= small_r;
  body.changed= true;

  body_margin.rel.radius= large_r;
  body_margin.changed= true;

  body_margin_kick.rel.radius= large_r;
  body_margin_kick.changed= true;

  body_dir.rel.p2.x= large_r;
  body_dir.changed= true;

  head_dir.rel.p2.x= large_r;
  head_dir.changed= true;
}

void VisualPlayer::set_head_angle( const Angle & a) { 
  head_frame_chg= true;
  head_frame.set_angle(a);
}

void VisualPlayer::set_label(const char * lab) {
  label.content.cur_size= 1;
  if ( !lab || *lab == '\0')
    return;

  while ( label.content.cur_size < label.content.max_size 
	  && *lab != '\0') {
    label.content.tab[label.content.cur_size]= *lab;
    lab++;
    label.content.cur_size++;
  }
}

void VisualPlayer::set_active(bool flag) {
  if (flag == is_active)
    return;

  is_active= flag;

  if (!is_active) {
    body_bg.set_color(c_invalid);
    return;
  }

  is_goalie= false;

  if (is_goalie)
    body_bg.set_color(c_goalie);
  else
    body_bg.set_color(c_player);
}

void VisualPlayer::set_goalie(bool flag) {
  if (flag == is_goalie)
    return;

  is_goalie= flag;

  if (!is_active)
    return;

  if (is_goalie)
    body_bg.set_color(c_goalie);
  else
    body_bg.set_color(c_player);
}

/******************************************************************************/


const double VisualField::FIELD_LENGTH                = 105.0;
const double VisualField::FIELD_WIDTH                 = 68.0;
//const double VisualField::FIELD_MARGIN                = 5.0;
const double VisualField::FIELD_CENTER_CIRCLE_R       = 9.15;
const double VisualField::FIELD_PENALTY_AREA_LENGTH   = 16.5;
const double VisualField::FIELD_PENALTY_AREA_WIDTH    = 40.32;
const double VisualField::FIELD_GOAL_AREA_LENGTH      = 5.5;
const double VisualField::FIELD_GOAL_AREA_WIDTH       = 18.32;
const double VisualField::FIELD_GOAL_WIDTH            = 14.02;////7.32;
const double VisualField::FIELD_GOAL_DEPTH            = 2.44;
const double VisualField::FIELD_PENALTY_SPOT_DIST     = 11.0;
const double VisualField::FIELD_CORNER_ARC_R          = 1.0;
//const double FIELD_CORNER_KICK_MARGIN    = 1.0;

const double VisualField::hlen= 105. * 0.5;      // FIELD_LENGTH * 0.5
const double VisualField::hwid= 68.  * 0.5;       // FIELD_WIDTH * 0.5

const double VisualField::pen_x= 105. *0.5 - 16.5; // hlen- FIELD_PENALTY_AREA_LENGTH;
const double VisualField::pen_y= 18.32 / 2.0; // FIELD_PENALTY_AREA_WIDTH/2.0;
const double VisualField::goal_x= 105. * 0.5 - 5.5; // hlen-FIELD_GOAL_AREA_LENGTH;
const double VisualField::goal_y= 18.32 / 2.0; //FIELD_GOAL_AREA_WIDTH/2.0;

VisualField::VisualField() { 
}

void VisualField::init(int my_key, int my_layer, 
		       const RGBcolor & my_c_line,
		       const RGBcolor & my_c_goal) {
  key= my_key;
  layer= my_layer;

  c_line= my_c_line;
  c_goal= my_c_goal;
  c_black= RGBcolor(0,0,0);
  c_white= RGBcolor(255,255,255);
  c_red=   RGBcolor(255,0,0);

  changed= true;

  //penalty points
  Point2d pp[4];
  pp[0]= Point2d(-hlen+FIELD_PENALTY_SPOT_DIST,0);
  pp[1]= Point2d( hlen-FIELD_PENALTY_SPOT_DIST,0);
  points.set_points(2,pp);
  points.set_color(c_line);
  points.use_intersects_area= false;

  //lines
  Line2d ll[20];
  //field lines
  ll[0]= Line2d( Point2d(-hlen,-hwid),Point2d( hlen,-hwid));
  ll[1]= Line2d( Point2d( hlen,-hwid),Point2d( hlen,+hwid));
  ll[2]= Line2d( Point2d( hlen,+hwid),Point2d(-hlen,+hwid));
  ll[3]= Line2d( Point2d(-hlen,+hwid),Point2d(-hlen,-hwid));
  //middle line
  ll[4]= Line2d( Point2d(    0,-hwid),Point2d(    0,+hwid));
  //left penalty area
  ll[5]= Line2d( Point2d(-hlen,-pen_y),Point2d(-pen_x,-pen_y));
  ll[6]= Line2d( Point2d(-pen_x,-pen_y),Point2d(-pen_x, pen_y));
  ll[7]= Line2d( Point2d(-pen_x, pen_y),Point2d(-hlen, pen_y));
  //left goal area
  ll[8]= Line2d( Point2d(-hlen,-goal_y),Point2d(-goal_x,-goal_y));
  ll[9]= Line2d( Point2d(-goal_x,-goal_y),Point2d(-goal_x, goal_y));
  ll[10]= Line2d( Point2d(-goal_x, goal_y),Point2d(-hlen, goal_y));
  //right penalty area
  ll[11]= Line2d( Point2d( hlen,-pen_y),Point2d( pen_x,-pen_y));
  ll[12]= Line2d( Point2d( pen_x,-pen_y),Point2d( pen_x, pen_y));
  ll[13]= Line2d( Point2d( pen_x, pen_y),Point2d( hlen, pen_y));
  //right goal area
  ll[14]= Line2d( Point2d( hlen,-goal_y),Point2d( goal_x,-goal_y));
  ll[15]= Line2d( Point2d( goal_x,-goal_y),Point2d( goal_x, goal_y));
  ll[16]= Line2d( Point2d( goal_x, goal_y),Point2d( hlen, goal_y));
  
  lines.set_lines(17,ll);
  lines.set_color(c_line);
  lines.use_intersects_area= false;

  //cirlces
  CircleArc2d ca[5];
  //center circle
  ca[0]= CircleArc2d(Point2d(0.0,0.0),FIELD_CENTER_CIRCLE_R,0.0,2.0*M_PI);
  //edge circlearcs
  ca[1]= CircleArc2d(Point2d(-hlen,-hwid),FIELD_CORNER_ARC_R,0.0,0.5*M_PI);
  ca[2]= CircleArc2d(Point2d( hlen,-hwid),FIELD_CORNER_ARC_R,0.5*M_PI,M_PI);
  ca[3]= CircleArc2d(Point2d( hlen, hwid),FIELD_CORNER_ARC_R,M_PI,1.5*M_PI);
  ca[4]= CircleArc2d(Point2d(-hlen, hwid),FIELD_CORNER_ARC_R,1.5*M_PI,2.0*M_PI);
  circlearcs.set_circlearcs(5,ca);
  circlearcs.set_color(c_line);
  circlearcs.use_intersects_area= false;

  //left goal
  pp[0]= Point2d(-hlen,-FIELD_GOAL_WIDTH*0.5);
  pp[1]= Point2d(-(hlen+ FIELD_GOAL_DEPTH),-FIELD_GOAL_WIDTH*0.5);
  pp[2]= Point2d(-(hlen+ FIELD_GOAL_DEPTH),+FIELD_GOAL_WIDTH*0.5);
  pp[3]= Point2d(-hlen,FIELD_GOAL_WIDTH*0.5);
  goal_l.set_points(4,pp);
  goal_l.set_color(c_goal);
  goal_l.filled= true;
  goal_l.use_intersects_area= false;

  //right goal
  pp[0]= Point2d(hlen,-FIELD_GOAL_WIDTH*0.5);
  pp[1]= Point2d(hlen+ FIELD_GOAL_DEPTH,-FIELD_GOAL_WIDTH*0.5);
  pp[2]= Point2d(hlen+ FIELD_GOAL_DEPTH,+FIELD_GOAL_WIDTH*0.5);
  pp[3]= Point2d(hlen,FIELD_GOAL_WIDTH*0.5);
  goal_r.set_points(4,pp);
  goal_r.set_color(c_goal);
  goal_r.filled= true;
  goal_r.use_intersects_area= false;

  //vertical stripe
  pp[0]= Point2d(0,-FIELD_WIDTH*0.5);
  pp[1]= Point2d(20, -FIELD_WIDTH*0.5);
  pp[2]= Point2d(20,  FIELD_WIDTH*0.5);
  pp[3]= Point2d(0,  FIELD_WIDTH*0.5);
  vertical_stripe.set_points(4,pp);
  vertical_stripe.set_color(c_red);
  vertical_stripe.filled= true;
  vertical_stripe.use_intersects_area= false;
  use_vertical_stripe(false);
}

void VisualField::draw(DisplayBase * disp, const Area2d & area, const Frame2d & p_frame, bool chg) {
  changed= changed || chg;

  vertical_stripe.draw(disp,area,p_frame,changed);

  points.draw(disp,area,p_frame,changed);
  goal_l.draw(disp,area,p_frame,changed);
  goal_r.draw(disp,area,p_frame,changed);

  lines.draw(disp,area,p_frame,changed);
  circlearcs.draw(disp,area,p_frame,changed);

  changed= false;
}

void VisualField::actualize(const Frame2d& f, bool chg) {
  changed= changed || chg;

  goal_l.actualize(f,changed);
  goal_r.actualize(f,changed);
  lines.actualize(f,changed);
  circlearcs.actualize(f,changed);

  changed= false;
}

void VisualField::set_goal_width( double width ) { 
  //cerr << "\nchanging goal width to " << width << flush;

  goal_l.rel.tab[0].y= -width*0.5;
  goal_l.rel.tab[1].y= -width*0.5;
  goal_l.rel.tab[2].y= +width*0.5;
  goal_l.rel.tab[3].y= +width*0.5;
  goal_l.changed= true;

  goal_r.rel.tab[0].y= -width*0.5;
  goal_r.rel.tab[1].y= -width*0.5;
  goal_r.rel.tab[2].y= +width*0.5;
  goal_r.rel.tab[3].y= +width*0.5;
  goal_r.changed= true;
}

/******************************************************************************/

const int SMonitorDevice::Options::info_level_min= 0;
const int SMonitorDevice::Options::info_level_def= 1;
const int SMonitorDevice::Options::info_level_max= 3;
const int SMonitorDevice::Options::scale_level_min= 0;
const int SMonitorDevice::Options::scale_level_def= 0;
const int SMonitorDevice::Options::scale_level_max= 5;
const double SMonitorDevice::Options::scale_level_inc= 0.2;
const double SMonitorDevice::Options::scale_level_beg= 1.0;
const int SMonitorDevice::Options::MODE_STANDARD= 0;
const int SMonitorDevice::Options::MODE_MOVE= 1;
const int SMonitorDevice::Options::MODE_SHOW_VIEW_AREA= 2;

SMonitorDevice::Options::Options() {
  server_port= 6000;
  strcpy(server_host,"localhost");
  coach_port= server_port+1;
  protocol_version= 2;
  connect_on_start= true;

  list_player_types= false;
  show_ball_collisions= false;
  just_edit= false;
  track_ball= false;
  show_ball_vel= false;

  player_radius= 0.3;
  player_skin= 1;
  kick_radius= 1.085;
  ball_radius= 0.3;//0.085;
  ball_skin= 1;


  c_team_l= RGBcolor(255,255,0);
  c_goalie_l= RGBcolor(0,255,0);
  c_font_l= RGBcolor(255,0,0);//(255,0,0);
  c_invalid_l= RGBcolor(0,0,0);
  
  c_team_r= RGBcolor(0,255,255);
  c_goalie_r= RGBcolor(255,153,255);
  c_font_r= RGBcolor(0,255,0);//(255,0,0);
  c_invalid_r= RGBcolor(0,0,0);
 

  c_ball= RGBcolor(255,255,255);
  c_field= RGBcolor(0,153,0);//(153,204,51); //(204,204,204);
  c_marigin= RGBcolor(204,51,51);
  c_line= RGBcolor(255,255,255);
  c_goal= RGBcolor(0,0,0);

  c_varea_exact= RGBcolor(0,180,0); // 0, 0xB4, 0
  c_varea_fuzzy= RGBcolor(0,170,0); // 0, 0xAA, 0

  info_level= info_level_def;
  scale_level= scale_level_def;

  mode= MODE_STANDARD;
  //mode= MODE_SHOW_VIEW_AREA;
  active_in_mode= id_invalid;

  lt_show_spare_space_to_offside_line= false;
  rt_show_spare_space_to_offside_line= false;
}

double SMonitorDevice::Options::scale_factor() const { 
  return scale_level_beg + scale_level * scale_level_inc; 
}

bool SMonitorDevice::Options::set_scale_level_from_double(double s) {
  for (int i=scale_level_max; i >= 0; i--)      
    if ( s >=  scale_level_beg + i * scale_level_inc - 0.0001) {
      scale_level=  i;
      return true;
    }
  scale_level= scale_level_min;
  return true;
}

const char * SMonitorDevice::Options::get_mode_string() const {
  if (mode == MODE_STANDARD)
    return "mode std ";
  if (mode == MODE_MOVE)
    return "mode move";
  if (mode == MODE_SHOW_VIEW_AREA)
    return "mode view";
  return "mode ????";
}

const char * SMonitorDevice::Options::get_mode_value_string() const {
  if (mode == MODE_STANDARD)
    return "std";
  if (mode == MODE_MOVE)
    return "move";
  if (mode == MODE_SHOW_VIEW_AREA)
    return "view";
  return "????";
}

bool SMonitorDevice::Options::set_mode_from_string(const char * s) {
  if ( strcmp("std",s) == 0)
    mode= MODE_STANDARD;
  else if ( strcmp("move",s) == 0)
    mode= MODE_MOVE;
  else if ( strcmp("view",s) == 0)
    mode= MODE_SHOW_VIEW_AREA;
  else
    return false;
  return true;
}


SMonitorDevice::ServerState::ServerState() {
  reset();
}

void SMonitorDevice::ServerState::reset() {
  //last_packet_ms_time= -1;
  reconnected= true;
  left_teamname.reset();
  right_teamname.reset();
  match_information.reset();
}

void SMonitorDevice::Positions::set_player(int i,const Point2d & p,const Angle & a) {
  player[i].pos= p;
  player[i].body_angle= a;
}

bool SMonitorDevice::Positions::max_x_pos(int p1, int p2, double & x1) const {
  bool res= false;
  for (int i=p1; i < p2; i++) {
    const Player & p = player[i];
    if ( ! p.alive) 
      continue;

    if (!res) {
      x1= p.pos.x;
      res= true;
    }
    else if ( p.pos.x > x1) 
      x1= p.pos.x;
  }
  return res;
}

//copy of max_x_pos with > replaced by <
bool SMonitorDevice::Positions::min_x_pos(int p1, int p2, double & x1) const {
  bool res= false;
  for (int i=p1; i < p2; i++) {
    const Player & p = player[i];
    if ( ! p.alive) 
      continue;

    if (!res) {
      x1= p.pos.x;
      res= true;
    }
    else if ( p.pos.x < x1) 
      x1= p.pos.x;
  }
  return res;
}

bool SMonitorDevice::Positions::max_x_pos(int p1, int p2, double & x1, double & x2) const {
  int res= 0;
  for (int i=p1; i < p2; i++) {
    const Player & p = player[i];

    if (!p.alive) 
      continue;

    if (res == 0) {
      x1= p.pos.x;
      res= 1;
    }
    else if (res == 1) {
      res= 2;
      if (p.pos.x > x1) {
	x2= x1;
	x1= p.pos.x;
      }
      else
	x2= p.pos.x;
    }
    else if ( p.pos.x > x2) {
      if ( p.pos.x > x1) {
	x2= x1;
	x1= p.pos.x;
      }
      else
	x2= p.pos.x;
    }
  }
  return (res==2);
}
//copy of max_x_pos with > replaced by <
bool SMonitorDevice::Positions::min_x_pos(int p1, int p2, double & x1, double & x2) const {
  int res= 0;
  for (int i=p1; i < p2; i++) {
    const Player & p = player[i];

    if (!p.alive) 
      continue;

    if (res == 0) {
      x1= p.pos.x;
      res= 1;
    }
    else if (res == 1) {
      res= 2;
      if (p.pos.x < x1) {
	x2= x1;
	x1= p.pos.x;
      }
      else
	x2= p.pos.x;
    }
    else if ( p.pos.x < x2) {
      if ( p.pos.x < x1) {
	x2= x1;
	x1= p.pos.x;
      }
      else
	x2= p.pos.x;
    }
  }
  return (res==2);
}

void SMonitorDevice::Positions::print_inline(ostream & out) {
  int prec= 4;
  out << setprecision(prec) << ball.pos.x 
      << " " << setprecision(prec) << ball.pos.y 
      << " " << setprecision(prec) << ball.vel.x 
      << " " << setprecision(prec) << ball.vel.y;
  for (int i= 0; i < MAX_PLAYER*2; i++) 
    out << "    " << setprecision(prec) << player[i].pos.x 
	<< " " << setprecision(prec) << player[i].pos.y 
	<< " " << setprecision(prec) << player[i].body_angle.get_value()
	<< " 0 0"; // the velocity is 0
}

void SMonitorDevice::Positions::print_formation(ostream & out, bool left_half, bool left_team) {
  int start_idx= 0;
  double dum= 0.0;
  if (left_half) {
    out << "\n[left half";
    dum= 52.5;
  }
  else
    out << "\n[right half";

  if (left_team) 
    out << ", left team]";
  else {
    out << ", right team]";
    start_idx= 11;
  }

  char buffer[200];
  for (int i= 1+start_idx; i< MAX_PLAYER+start_idx; i++) {
    float x= (player[i].pos.x + dum)/52.5;
    if (x<0.0) x= 0.0;
    if (x>1.0) x= 1.0;
    float y= (player[i].pos.y + 34.0)/68.0;
    if (y<0.0) y= 0.0;
    if (y>1.0) y= 1.0;
    sprintf(buffer,"\npos_%-2d = %.2f %.2f *",i-start_idx,x,y);
    out << buffer;
  }

  out << flush;
}
/*****************************************************************************/
/*****************************************************************************/
double x_SERVER_2_LP(double x) {
  return x;
}

double y_SERVER_2_LP(double y) {
  return -y;
}

double ang_SERVER_2_LP(double a) {
  a= (a*PI)/180.0;
  if (a < 0.0) return -a;
  return -a+2*PI;
}
/*****************************************************************************/
/*****************************************************************************/

SMonitorDevice::SMonitorDevice() {
  server_state.reset();
  //init_connection(); //vorlaeufig
}

void SMonitorDevice::generic_description_of_options(ostream & o, int mode) const {
  print_option_entry(o,mode,"port",options.server_port,"defines the socket port for communication");
  print_option_entry(o,mode,"host",options.server_host,"defines the host on which the soccer server is running");
  print_option_entry(o,mode,"version",options.protocol_version,"version of monitor <-> server protocol");
  print_option_entry(o,mode,"connect_on_start",options.connect_on_start,"if set then a connection to the server is established during the start");
  print_option_entry(o,mode,"list_player_types",options.list_player_types,"print all player types after a connection");
  print_option_entry(o,mode,"show_ball_collisions",options.show_ball_collisions,"show if a player collides with the  ball");
  print_option_entry(o,mode,"just_edit",options.just_edit,"don't connect to the soccer server");
  print_option_entry(o,mode,"scale",options.scale_factor(),"factor all player's and the ball sizes are multiplied by");
  print_option_entry(o,mode,"detail",options.info_level,"level of player information such as his number, stamina and type");
  print_option_entry(o,mode,"mode",options.get_mode_value_string(),"initial mode to use");
  print_option_entry(o,mode,"player_radius",options.player_radius,"default inner player radius (if server doesn't provide type info)");
  print_option_entry(o,mode,"kick_radius",options.kick_radius,"default outer player radius (if server doesn't provide type info)");
  print_option_entry(o,mode,"player_num_pos_x",options.player_num_pos.x,"x position of player number relative to player's center");
  print_option_entry(o,mode,"player_num_pos_y",options.player_num_pos.y,"y position of player number relative to player's center");

  print_option_entry(o,mode,"ball_radius",options.ball_radius,"define how large the inner circle of the ball should be");
  o << "\n";
  print_option_entry(o,mode,"c_team_l",options.c_team_l,"color of left team players");
  print_option_entry(o,mode,"c_goalie_l",options.c_goalie_l,"color of left goalie");
  print_option_entry(o,mode,"c_font_l",options.c_font_l,"color of left team number strings");
  print_option_entry(o,mode,"c_team_r",options.c_team_r,"color of right team players");
  print_option_entry(o,mode,"c_goalie_r",options.c_goalie_r,"color of right goalie");
  print_option_entry(o,mode,"c_font_r",options.c_font_r,"color of right team number strings");
  print_option_entry(o,mode,"c_ball",options.c_ball,"color of the ball");
  print_option_entry(o,mode,"c_field",options.c_field,"color of the soccer field");
  print_option_entry(o,mode,"c_line",options.c_line,"color of the soccer field lines");
  print_option_entry(o,mode,"c_goal",options.c_goal,"color of the soccer field goals");
  print_option_entry(o,mode,"c_varea_exact",options.c_varea_exact,"color of the exact view area");
  print_option_entry(o,mode,"c_varea_fuzzy",options.c_varea_fuzzy,"color of the fuzzy view area");
  o << "\n";
}

bool SMonitorDevice::process_options(const ValueParser & vp) {
  double tmp_double;
  int res;

  vp.get("port", options.server_port);
  vp.get("host", options.server_host,STRING_MAX_SIZE);

#if USE_COACH
  vp.get("coach_port", options.coach_port);
#endif
  vp.get("version", options.protocol_version);
  vp.get("connect_on_start",options.connect_on_start);

  vp.get("list_player_types",options.list_player_types);
  vp.get("show_ball_collisions",options.show_ball_collisions);
  vp.get("just_edit",options.just_edit);

  res= vp.get("scale",tmp_double);
  if ( res == 1 ) 
    options.set_scale_level_from_double(tmp_double);

  vp.get("detail", options.info_level);
  if (options.info_level < options.info_level_min)
    options.info_level= options.info_level_min;
  else if (options.info_level > options.info_level_max)
    options.info_level= options.info_level_max;

  char tmp_str[MAX_NAME_LEN];
  res= vp.get("mode",tmp_str,MAX_NAME_LEN);
  if ( res > 0 ) {
    cout << "\nsetting mode [" << tmp_str << "]";
    options.set_mode_from_string(tmp_str);
    cout << "\nnew mode: " << options.get_mode_string() << flush;
  }

  vp.get("player_radius",options.player_radius);
  vp.get("player_skin",options.player_skin);
  vp.get("kick_radius",options.kick_radius);
  vp.get("player_num_pos_x",options.player_num_pos.x);
  vp.get("player_num_pos_y",options.player_num_pos.y);
  vp.get("ball_radius",options.ball_radius);
  vp.get("ball_skin",options.ball_skin);   

  char rgb_str[20];
  vp.get("c_team_l",rgb_str,20,'\0');   AsciiProcessor::get_col(rgb_str,options.c_team_l);
  vp.get("c_goalie_l",rgb_str,20,'\0'); AsciiProcessor::get_col(rgb_str,options.c_goalie_l);
  vp.get("c_font_l",rgb_str,20,'\0');   AsciiProcessor::get_col(rgb_str,options.c_font_l);
  
  vp.get("c_team_r",rgb_str,20,'\0');   AsciiProcessor::get_col(rgb_str,options.c_team_r);
  vp.get("c_goalie_r",rgb_str,20,'\0'); AsciiProcessor::get_col(rgb_str,options.c_goalie_r);
  vp.get("c_font_r",rgb_str,20,'\0');   AsciiProcessor::get_col(rgb_str,options.c_font_r);
  
  vp.get("c_ball",rgb_str,20,'\0');     AsciiProcessor::get_col(rgb_str,options.c_ball);
  vp.get("c_field",rgb_str,20,'\0');    AsciiProcessor::get_col(rgb_str,options.c_field);
  vp.get("c_marigin",rgb_str,20,'\0');  AsciiProcessor::get_col(rgb_str,options.c_marigin);
  vp.get("c_line",rgb_str,20,'\0');     AsciiProcessor::get_col(rgb_str,options.c_line);
  vp.get("c_goal",rgb_str,20,'\0');     AsciiProcessor::get_col(rgb_str,options.c_goal);

  vp.get("c_varea_exact",rgb_str,20,'\0'); AsciiProcessor::get_col(rgb_str,options.c_varea_exact);
  vp.get("c_varea_fuzzy",rgb_str,20,'\0'); AsciiProcessor::get_col(rgb_str,options.c_varea_fuzzy);

  if ( vp.num_of_not_accessed_entries() ) {
    ERROR_OUT << "\nSMonitorDevice: not recognized options:";
    vp.show_not_accessed_entries(ERROR_STREAM); 
    return false;
  }

  return true;
}

bool SMonitorDevice::process_options(const char * fname) {
  ValueParser vp(fname,"SMonitorDevice");
  return process_options(vp);
}

bool SMonitorDevice::process_options(int argc, char const* const* argv) {
  ValueParser vp(argc,argv,"m_");
  return process_options(vp);
}

void SMonitorDevice:: help_char_command(ostream & o) const { 
  o << "\n"
    << "server commands:\n"
    << "b = drop ball at current mouse pointer position\n"
    << "c = connect to server\n"
    << "l = free kick for left team\n"
    << "r = free kick for right team\n"
    << "s = start a match\n"
    << "\n"
    << "monitor commands:\n"
    << "m = toggle move/view mode\n"
    << "p = print current positions on cout\n"
    << "P = print current formation (for left or right)\n"
    << "v = toggle displaying future ball position and velocity"
//      << "T = toggle tracking of the ball\n"
    << "\n"
    << "coach commands:\n"
    << "t = toggle current team (starts with left team)\n"
    << "i = position player (of the current team) with number i at mouse pointer position\n"
    << "    i can take following values: 1,2,3,4,5,6,7,8,9\n"
    << "                                 A or 0 which means 10\n"
    << "		                 B which means 11\n";
}

void SMonitorDevice::help_options(ostream & o) const {
  o << "\nsoccer monitor options:"
    << "\n"
    << "\n(all colors are define by their rrggbb values)";

  generic_description_of_options(o,1);
}

void SMonitorDevice::generate_file_options(ostream & o) const {
  o << "\n[SMonitorDevice]"
    << "\n"
    << "\n### all options can be used on the command line if prefixed with '-m_'"
    << "\n### for example '-m_host localhost' will specify the host of the soccer server"
    << "\n"
    << "\n#color options: all colors are define by their rrggbb values"
    << "\n";
  generic_description_of_options(o,0);
}

bool SMonitorDevice::process_char_command(BuilderBase * build, MenuBase * menu, const InputEvent & event) {
  bool redraw= false;
  //static char buf[100];
  //ostrstream dum_str(buf,100);
  switch (event.key) {
  case 'c':
    if ( options.just_edit ) {
      cout << "\nthis key is not set in edit mode";
      break;
    }
    server.init_serv_addr(options.server_host,options.server_port);
    send_dispinit();
    server_state.reset();
    break;
  case 'l': 
    if ( options.just_edit ) {
      cout << "\nthis key is not set in edit mode";
      break;
    }
    send_dispfoul_left(event.pos);
    break;
#if 1
  case 'm': 
    options.active_in_mode= id_invalid;
    if ( options.mode == Options::MODE_STANDARD) {
      options.mode= Options::MODE_MOVE;
    }
    else if ( options.mode == Options::MODE_MOVE) {
      build->set_cmd_set_frame_visible(frame_shadow,0);
      options.mode= Options::MODE_SHOW_VIEW_AREA;
    }
    else if ( options.mode== Options::MODE_SHOW_VIEW_AREA) {
      build->set_cmd_set_frame_visible(frame_varea,0);
      options.mode= Options::MODE_STANDARD;
    }
    menu->set_button_label(BUTTON_MODE,options.get_mode_string());
    return true;
    break;
#endif
  case 'p': 
    cout << "\n";
    server_pos.print_inline(cout);
    cout << flush;
    break;
  case 'P': 
    cout << "\n";
    server_pos.print_formation(cout,coach_state.left_team, coach_state.left_team);
    cout << flush;
    break;
  case 'T': 
    //options.toggle_track_ball();
    break;
  case 'r': 
    if ( options.just_edit ) {
      cout << "\nthis key is not set in edit mode";
      break;
    }
    send_dispfoul_right(event.pos);
    break;
  case 's':
    if ( options.just_edit ) {
      cout << "\nthis key is not set in edit mode";
      break;
    }
    //server.init_serv_addr(options.server_host,options.server_port);
    send_dispstart();
    break;
  case 'v':
    options.toggle_show_ball_vel();
    if ( options.show_ball_vel ) {
      vis_ball.set_show_vel( server_pos.ball.vel );
    } 
    else {
      vis_ball.unset_show_vel();
    }
    return true;
    break;
  case '>':
    break; // just a debugging feature
    if (options.lt_show_spare_space_to_offside_line)
      options.lt_show_spare_space_to_offside_line= false;
    else {
      options.lt_show_spare_space_to_offside_line= true;
      options.rt_show_spare_space_to_offside_line= false;
    }
    break;
  case '<':
    break; //just a debugging feature
    if (options.rt_show_spare_space_to_offside_line)
      options.rt_show_spare_space_to_offside_line= false;
    else {
      options.rt_show_spare_space_to_offside_line= true;
      options.lt_show_spare_space_to_offside_line= false;
    }
    break;
  }

  int o_id= id_invalid;
  if ( 'b' == event.key ) o_id= id_ball;
  else if ( 'A' == event.key || '0' == event.key) o_id= 9; 
  else if ( 'B' == event.key ) o_id= 10;
  else o_id= int(event.key)-49;
  if ( p_valid(o_id) && !coach_state.left_team) o_id += 11;
  
  if ( options.mode == Options::MODE_MOVE && o_valid(o_id) || id_ball == o_id) {
    if ( options.just_edit) {
      set_object_pos(build,o_id,event.pos);
      return true;
    }
    else {
#if 1 // if there is no connection to the server, this is needed
      send_object_pos(o_id,event.pos);
      set_object_pos(build,o_id,event.pos); 
      return true;
#else      
      send_object_pos(o_id,event.pos);	
      return false; //don't redraw
#endif    
    }
  }
  
  if ( options.mode == Options::MODE_SHOW_VIEW_AREA && p_valid( o_id ) ) {
    if (options.active_in_mode == o_id) {
      options.active_in_mode= id_invalid;
      build->set_cmd_set_frame_visible(frame_varea,0);
    }
    else {
      options.active_in_mode= o_id;
      Positions::Player & p= server_pos.ref_player(options.active_in_mode);
      build->set_cmd_set_frame_pos_ang(frame_varea,p.pos,p.body_angle+p.head_angle_rel);
      vis_view_area.set_view_mode(p.view_quality, p.view_width);
      build->set_cmd_set_frame_visible(frame_varea,1);
    }
    return true; //redraw
  }

  switch (event.key) {
  case 't': coach_state.toggle_team(); break;
  case 'e': 
#if 0
    if ( options.just_edit ) {
      cout << "\nthis key is not set in edit mode";
      break;
    }
    coach.send_msg("(ear on)",9);
#else
    cout << "\nthis key is not set anymore";
#endif
    break;
    //case 'm': COACH::sock.send_msg("(change_mode play_on)",22);
  }
  return redraw;
}

bool SMonitorDevice::process_mouse_button_event(BuilderBase * build, const InputEvent & event) {
  //options.active_in_mode= id_invalid;
  static unsigned long last_time=0;
  //if (event.mouse_button != 2)
  //  return false;
  
  if ( event.mouse_button == 2 &&
       event.mouse_button_state == InputEvent::MOUSE_BUTTON_PRESSED ) {
    Point2d rel;
    double min= 100.0;
    int p_min= id_invalid;
    for (int i=0; i<MAX_PLAYER*2; i++) {
      rel.x= event.pos.x - server_pos.player[i].pos.x;
      rel.y= event.pos.y - server_pos.player[i].pos.y;
      
      //take the greater absolute value 
      double dum=  fabs(rel.x) > fabs(rel.y) ? fabs(rel.x) : fabs(rel.y);

      if ( dum < min ) {
	min= dum;
	p_min= i;
      }
    }
    rel.x= event.pos.x - server_pos.ball.pos.x;
    rel.y= event.pos.y - server_pos.ball.pos.y;
    double dum=  fabs(rel.x) > fabs(rel.y) ? fabs(rel.x) : fabs(rel.y);
    if ( dum < min ) {
      min= dum;
      p_min= id_ball;
    }
    if ( min <= options.kick_radius * 1.5 * options.scale_factor() )
      options.active_in_mode= p_min;
    else
      options.active_in_mode= id_invalid;
    //cout << "\noptions.active_in_mode= " << options.active_in_mode << flush;
    if ( options.mode == Options::MODE_MOVE ) {
      if ( o_valid(options.active_in_mode) ) {
	build->set_cmd_set_frame_pos(frame_shadow, event.pos);
	build->set_cmd_set_frame_visible(frame_shadow,1);
      }
    }
    else if ( options.mode == Options::MODE_SHOW_VIEW_AREA ) {
      if ( !p_valid( options.active_in_mode)) 
	build->set_cmd_set_frame_visible(frame_varea,0);
      else {
	Positions::Player & p= server_pos.ref_player(options.active_in_mode);
	build->set_cmd_set_frame_pos_ang(frame_varea,p.pos,p.body_angle+p.head_angle_rel);
	vis_view_area.set_view_mode(p.view_quality, p.view_width);
	build->set_cmd_set_frame_visible(frame_varea,1);
      }
      return true; //redraw
    }
    //cout << "\n>>>>>>>>>>>>>>>>>>>> min= " << min << " " << options.kick_radius * 1.5;
    return false; //no need for redraw
  }

  if ( event.mouse_button_state == InputEvent::MOUSE_BUTTON_MOTION && options.mode == Options::MODE_MOVE) 
    if ( p_valid( options.active_in_mode) && 
	 (event.time-last_time> 75 || last_time-event.time>75) ) {
      build->set_cmd_set_frame_pos(p_frame(options.active_in_mode), event.pos);
      last_time= event.time;
      return true;
    }
    else if ( o_ball(options.active_in_mode) && 
	      (event.time-last_time> 75 || last_time-event.time>75) ) {
      build->set_cmd_set_frame_pos(frame_ball, event.pos);
      last_time= event.time;
      return true;
    }
    else
      return false;

  if ( event.mouse_button == 2 &&
       event.mouse_button_state == InputEvent::MOUSE_BUTTON_RELEASED && options.mode == Options::MODE_MOVE) {
    if ( !o_valid(options.active_in_mode) ) 
      return false;
    
    bool res= false;
    if (options.just_edit) {
      set_object_pos(build,options.active_in_mode, event.pos);
      res= true;
    }
    else {
#if 1
      set_object_pos(build,options.active_in_mode, event.pos); //is needed 
      res= true;                       // when no connection to a server is established
#endif
      send_object_pos(options.active_in_mode, event.pos); //send new pos to server!
    }

    build->set_cmd_set_frame_visible(frame_shadow,0);
    last_time= 0;
    options.active_in_mode= id_invalid;
    return res;
  }

  return false;
}

bool SMonitorDevice::process_menu_button(BuilderBase * build, MenuBase * menu, const InputEvent & event) {
  char buf[20];
  bool chg= false;
  //static unsigned long last_time=0;
  switch ( event.menu_button ) {
  case BUTTON_START:
    send_dispstart();
    return false;

  case BUTTON_RECONNECT:
    if ( options.just_edit ) {
      cout << "\nthis key is not set in edit mode";
      break;
    }
    server.init_serv_addr(options.server_host,options.server_port);
    send_dispinit();
    server_state.reset();
    return false;

  case BUTTON_SCALE_LEVEL:
    if (event.mouse_button==1) {
      chg= false;
      if (options.scale_level > options.scale_level_min) {
	options.scale_level--;
	chg= true;
      }
    }
    else {
      if (options.scale_level < options.scale_level_max) {
	options.scale_level++;
	chg= true;
      }
    }
    if (chg) {
      double scale= options.scale_factor();
      sprintf(buf,"scale %.1f", scale);
      menu->set_button_label(BUTTON_SCALE_LEVEL,buf);
      set_all_objects_scale(build, scale);
    }
    return chg;

  case BUTTON_INFO_LEVEL:
    if (event.mouse_button==1) {
      chg= false;
      if (options.info_level > options.info_level_min) {
	options.info_level--;
	chg= true;
      }
    }
    else {
      if (options.info_level < options.info_level_max) {
	options.info_level++;
	chg= true;
      }
    }
    if (chg) {
      sprintf(buf,"detail %d", options.info_level);
      vis_player_set_info_level(options.info_level);
      vis_ball_set_info_level(options.info_level);
      menu->set_button_label(BUTTON_INFO_LEVEL,buf);
    }
    return chg;

  case BUTTON_MODE:
    options.active_in_mode= id_invalid;

    chg= false;
    if (event.mouse_button==1) {
      if ( options.mode== Options::MODE_MOVE) {
	build->set_cmd_set_frame_visible(frame_shadow,0);
	options.mode= Options::MODE_STANDARD;
	chg= true;
      }
      else if ( options.mode== Options::MODE_SHOW_VIEW_AREA) {
	build->set_cmd_set_frame_visible(frame_varea,0);
	options.mode= Options::MODE_MOVE;
	chg= true;
      }
    }
    else {
      if ( options.mode== Options::MODE_STANDARD) {
	options.mode= Options::MODE_MOVE;
	chg= true;
      }
      else if ( options.mode== Options::MODE_MOVE) {
	build->set_cmd_set_frame_visible(frame_shadow,0);
	options.mode= Options::MODE_SHOW_VIEW_AREA;
	chg= true;
      }
    }
    if (chg)
      menu->set_button_label(BUTTON_MODE,options.get_mode_string());

    return chg;
  case BUTTON_UNZOOM:
    build->set_cmd_set_view_area(initial_area);
    return true;
  case BUTTON_QUIT:
    menu->set_exit_program();

    return false;

  }
  return false;
}  

bool SMonitorDevice::process_popup_button(BuilderBase * build, MenuBase * popup, const InputEvent & event) {
  static Point2d pos;

  //cout << "\npos= " << pos.x << "," << pos.y << flush;
  //cout << "\ninput_pos= " << event.pos.x << "," << event.pos.y << flush;

  if ( event.mouse_button_state == InputEvent::MOUSE_BUTTON_PRESSED) {
    pos= event.pos;
    return false; //don't redraw
  }

  switch (event.menu_button) {
  case POPUP_BUTTON_DROP_BALL:
    send_dispball( pos );
    //set_object_pos(build,id_ball, pos);
    break;
  case POPUP_BUTTON_FREE_KICK_LEFT:
    send_dispfoul_left( pos );
    //set_object_pos(build,id_ball, pos);
    break;
  case POPUP_BUTTON_FREE_KICK_RIGHT:
    send_dispfoul_right( pos );
    //set_object_pos(build,id_ball, pos);
    break;
  }
  //popup->set_menu_extended(false);
  return true;
};

bool SMonitorDevice::init_menu(MenuBase * menu) {
#ifdef WEBFIELD
  return false; //TEST
#endif
  char buf[20];
  menu->set_number_of_buttons(BUTTON_NUMBER);
  menu->set_button_label(BUTTON_START,"kick off");
  menu->set_button_label(BUTTON_RECONNECT,"connect");
  double scale= options.scale_factor();
  sprintf(buf,"scale %.1f", scale);
  menu->set_button_label(BUTTON_SCALE_LEVEL,buf);
  sprintf(buf,"detail %d", options.info_level);
  menu->set_button_label(BUTTON_INFO_LEVEL,buf);
  menu->set_button_label(BUTTON_MODE,options.get_mode_string());
  menu->set_button_label(BUTTON_UNZOOM,"unzoom");
  menu->set_button_label(BUTTON_QUIT,"quit");

  //menu->set_menu_extended(false);
  menu->set_menu_extended(true);
  return true;
};

bool SMonitorDevice::init_popup(MenuBase * popup) {
  popup->set_number_of_buttons(POPUP_BUTTON_NUMBER);
  popup->set_button_label(POPUP_BUTTON_DROP_BALL,"drop ball");
  popup->set_button_label(POPUP_BUTTON_FREE_KICK_LEFT,"free kick left");
  popup->set_button_label(POPUP_BUTTON_FREE_KICK_RIGHT,"free kick right");
  return false; //don't redraw!!!
};

bool SMonitorDevice::init_frames(BuilderBase * build){
  int layer= -1;

  RGBcolor c_black(0,0,0);
  RGBcolor c_red(255,0,0);

  //background
  build->set_cmd_set_background_color(options.c_field);

  //view area frame
  build->set_cmd_insert_frame(0,frame_varea,Point2d(2.0,0.0),0.0,layer-1);
  vis_view_area.init(0,0, options.c_varea_exact, options.c_varea_fuzzy);
  build->set_cmd_insert_visobject(frame_varea, & vis_view_area);
  build->set_cmd_set_frame_visible(frame_varea,0);

  //soccer field
  vis_field.init(0,layer,options.c_line,options.c_goal);
  build->set_cmd_insert_visobject(0, & vis_field);

  //PlayerTypes::init(options.ball_radius, options.player_radius, 
  PlayerTypes::init(0.085, options.player_radius, 
		    options.kick_radius - 0.085 - options.player_radius);

  //in this frame the logger drawings are displayed
  build->set_cmd_insert_frame(0, frame_canvas_left, Point2d(0.0,0.0),0.0, layer+4);
  build->set_cmd_insert_frame(0, frame_canvas_right, Point2d(0.0,0.0),M_PI, layer+4);

  double b_rad= options.ball_radius;
  double k_rad= options.kick_radius;
  //ball
  vis_ball.init(0,0, b_rad, k_rad,
		options.c_ball,
		c_red, c_red, c_black);

  server_pos.set_ball_pos(Point2d(2.0,0.0));
#ifdef WEBFIELD
  server_pos.set_ball_pos(Point2d(2.0,60.0));
#endif
  build->set_cmd_insert_frame(0,frame_ball, server_pos.ball.pos,0.0,layer+3);
  
  build->set_cmd_insert_visobject(frame_ball, & vis_ball);


#if 0
  if ( options.ball_skin == 2) {
    build->set_cmd_insert_f_circle(frame_ball,0,Circle2d(Point2d(0.0,0.0),b_rad),0,options.c_ball);
    build->set_cmd_insert_circle(frame_ball,1,Circle2d(Point2d(0.0,0.0),b_rad),0,options.c_ball);
  }
  else {
    build->set_cmd_insert_f_circle(frame_ball,0,Circle2d(Point2d(0.0,0.0),b_rad),0,options.c_ball);
    build->set_cmd_insert_point(frame_ball,1,Point2d(0.0,0.0),0,options.c_ball);
    //build->set_cmd_insert_circle(frame_ball,2,Circle2d(Point2d(0.0,0.0),b_rad*10),0,options.c_ball);
    build->set_cmd_insert_circle(frame_ball,2,Circle2d(Point2d(0.0,0.0), k_rad*0.8),0,options.c_ball);
  }
#endif
  //shadow
  build->set_cmd_insert_frame(0,frame_shadow,Point2d(2.0,0.0),0.0,layer+3);
  build->set_cmd_insert_circle(frame_shadow,0,Circle2d(Point2d(0.0,0.0), k_rad),0,c_black);
  build->set_cmd_insert_line(frame_shadow,0,Line2d(Point2d(-k_rad,0.0),Point2d(k_rad,0.0)),0,c_black);
  build->set_cmd_insert_line(frame_shadow,0,Line2d(Point2d(0.0,-k_rad),Point2d(0.0,k_rad)),0,c_black);
  build->set_cmd_set_frame_visible(frame_shadow,0);

  //players
  double init_y= 35.2;
#ifdef WEBFIELD
  init_y= 60;
#endif
  for (int i= 0; i<MAX_PLAYER*2; i++) {
    RGBcolor c_invalid= options.c_invalid_l;
    RGBcolor c_player= options.c_team_l;
    RGBcolor c_goalie= options.c_goalie_l;
    RGBcolor c_font= options.c_font_l;
    Point2d pos_player= Point2d(-8.0 -i*3.0*k_rad,init_y);
    if ( p_right(i) ) {
      c_invalid= options.c_invalid_r;
      c_player= options.c_team_r;
      c_goalie= options.c_goalie_r;
      c_font= options.c_font_r;
      //pos_player= Point2d(8.0 + (i-MAX_PLAYER)*3.0*k_rad,init_y);
      pos_player= Point2d(8.0 + (i-MAX_PLAYER)*3.0*k_rad,init_y);
    }
    server_pos.set_player(i,pos_player,0.0);
    build->set_cmd_insert_frame(0,p_frame(i),pos_player,0.0,layer+1);
    vis_player[i].init(0,0,p_char(i), c_invalid, c_player, c_goalie, c_font);
    build->set_cmd_insert_visobject(p_frame(i),vis_player+i);
    vis_player[i].set_label_pos( options.player_num_pos );
  }

  vis_player_set_info_level( options.info_level );
  vis_ball_set_info_level( options.info_level );

  double scale= options.scale_factor();
  if ( scale != 1.0 )
  set_all_objects_scale(build, scale);
  return true;
}

bool SMonitorDevice::init_connection() {
  if (options.just_edit)
    return true;

  server.init_socket_fd();
  //server.init_socket_fd(6010); //test to use client2dview with smonitor_dev.C
  server.set_fd_nonblock();
  server.init_serv_addr(options.server_host,options.server_port);

#if USE_COACH
  coach.init_socket_fd();
  coach.set_fd_nonblock();
  coach.init_serv_addr(options.server_host,options.coach_port);
#endif  

  if ( options.connect_on_start )
    send_dispinit();
  return true;
}

bool SMonitorDevice::uses_mouse() const {
  if (options.mode == Options::MODE_MOVE ||
      options.mode == Options::MODE_SHOW_VIEW_AREA)
    return true;
  return false;
}

bool SMonitorDevice::uses_popup() const {
  if (options.mode == Options::MODE_STANDARD)
    return true;
  return false;
}

bool SMonitorDevice::destruct() {
  send_dispbye();
  //some stuff should be still done here
  return true;
}

bool SMonitorDevice::process_input(fd_set * set, BuilderBase * build) {
  if (options.just_edit) 
    return true;

  char * buf;

  bool redraw= false;
  //process server commands
  if ( is_fd_in_set(server.socket_fd, set) ) {
    int num_bytes= 0;
    int msg_type;
    int num_show_msg= 0;

    buf= buffer1;
    while ( server.recv_msg( buf , num_bytes, true ) ) {
      //if (RUN::freeze) continue;
      msg_type= server_msg_type(buf);
      if (SHOW_MODE == msg_type) {
	if (num_bytes > 0) {
	  num_show_msg++;
	  //rotate the buf to keep the last show message in the other buffer!
	  if (buf == buffer1)
	    buf= buffer2;
	  else 
	    buf= buffer1;
	}
      }
      else if ( FRAMEVIEW_MODE == msg_type ) {
	bool res= server_interpret_frameview_msg(build,buf);
	redraw= redraw || res;
      }
      else if (MSG_MODE == msg_type) {
	bool res= server_interpret_msginfo_t(build, (void*)(buf));
	redraw= redraw || res;
      }
      else if (DRAW_MODE == msg_type) {
	bool res= server_interpret_drawinfo_t(build, (void*)(buf));
	redraw= redraw || res;
      }
      else if (NO_INFO == msg_type)
	cerr << "\nmode= NO_INFO not yet implemented";
      else if (BLANK_MODE == msg_type)
	cerr << "\nmode= BLANK_MODE not yet implemented";
      else if (PM_MODE == msg_type)
	cerr << "\nmode= PM_MODE not yet implemented";
      else if (TEAM_MODE == msg_type)
	cerr << "\nmode= TEAM_MODE not yet implemented";
      else if (PT_MODE == msg_type) {
	bool res= server_interpret_player_type_t(build, (void*)(buf));
	redraw= redraw || res;
      }
      else if (PARAM_MODE == msg_type) {	 //server parameters
	bool res= server_interpret_server_params_t(build, (void*)(buf));
	redraw= redraw || res;
      }
      else if (PPARAM_MODE == msg_type)
	;//cerr << "\nmode= PPARAM_MODE not yet implemented";
      else {
	ERROR_OUT << "\nunknown mode " << msg_type << " :";
	int i=0;
	while(i<50) {
	  if (isprint(buf[i])) 
	    cout << buf[i];
	  else 
	    break;
	  i++;
	}
	if (i>0) {
	  cout << "\nHINT: if you use server version < 7.02 repositioning of players"
	       << "\nmay couse such messages" << flush;
	}
      }
    }
    if ( num_show_msg > 0) { 
      //switch to the cached buffer
      if (buf == buffer1)
	buf= buffer2;
      else 
	buf= buffer1;

      bool res;
      if (options.protocol_version >= 2) 
	res= server_interpret_showinfo_t2(build, (void*)(buf));
      else
	res= server_interpret_showinfo_t(build, (void*)(buf));
      redraw= redraw || res;
      if (num_show_msg>1)
	cerr << "\nskipped " << num_show_msg-1 << " SHOW messages";
    }
  }
   
#if USE_COACH
  //process coach commands
  if ( is_fd_in_set( coach.socket_fd, set ) ) {
    int num_bytes;
    while ( coach.recv_msg( buffer[0] , num_bytes, true ) ) {
      buffer[0][num_bytes]= '\0';
      cerr << "\ncoach received: " << buffer[0] << endl;
    }
  }
#endif

  return redraw;
}

int  SMonitorDevice::set_fds(fd_set * set) { 
  if (options.just_edit)
    return -1;
  add_fd_to_set(server.socket_fd,set); 
#if USE_COACH
  add_fd_to_set(coach.socket_fd,set); 
  return server.socket_fd>coach.socket_fd?server.socket_fd:coach.socket_fd; 
#else
  return server.socket_fd; 
#endif

}

bool SMonitorDevice::got_fds(fd_set * set) { 
  if (options.just_edit)
    return false;
  if ( is_fd_in_set(server.socket_fd,set) ) return true;
#if USE_COACH
  return is_fd_in_set(coach.socket_fd,set);
#else
  return false;
#endif
}


/* private methods */
void SMonitorDevice::vis_ball_set_info_level(int lev) {
  if (lev >= 2) 
    vis_ball.set_show_vel_string( server_pos.ball.vel );
  else
    vis_ball.unset_show_vel_string();
}

void SMonitorDevice::vis_player_set_info_level(int lev, VisualPlayer & vis_p, const Positions::Player & p) {
  char dum[20];    
  vis_p.set_use_number(true);
  switch (options.info_level) {
  case 0:
    vis_p.set_use_number(false);
    break;
  case 2:  
    sprintf(dum," %d", (int)p.stamina);
    vis_p.set_label(dum);
    break;
  case 3: 
    sprintf(dum," %d, t%d", (int)p.stamina, p.type);
    vis_p.set_label(dum);
    break; 
  default:
    vis_p.set_label(0);
  }
}

void SMonitorDevice::vis_player_set_info_level(int lev) {
  for (int i=0; i < MAX_PLAYER*2; i++) {
    Positions::Player & p= server_pos.ref_player(i);
    VisualPlayer & vis_p= vis_player[i];
    vis_player_set_info_level(lev,vis_p,p);
  }

}

int SMonitorDevice::server_msg_type(void * ptr) {
  if  ( *((char*)ptr) == '_' )
    return FRAMEVIEW_MODE;
  SSrv::dispinfo_t *dispinfo_dum= (SSrv::dispinfo_t*)ptr;
  SSrv::dispinfo_t & dispinfo= *dispinfo_dum;
  return  (ntohs (dispinfo.mode));
}


bool SMonitorDevice::ins_simple_obj(const char * buf, int fref, BuilderBase * build,const char* & next) {
  const int idx_zero= 0;
  RGBcolor col;
  int num_entries;
  
  next= buf;
  strspace(next,next);
  if ( *next == 'l' ) 
    num_entries= 4;
  else if ( *next == 'c' ) 
    num_entries = 3;
  else if ( *next == 'p' )
    num_entries= 2;
  else
    return false;

  buf= next;
  next++;
  
  double dd[4];
  if ( num_entries != str2val(next, num_entries,dd,next) )
    return false;
 
  strspace(next,next);
  if ( next[0] == '#')
    next++;

  const char * dum;
  if ( next[0] != ';' ) 
    if ( AsciiProcessor::get_col(next,col,dum) ) 
      next= dum;
    else {
      //we need a copy of the color string
      char dum[100];
      dum[99]= '\0';
      for (int i=0; i<99; i++) {
	if (*next == ';' || *next == ' ' || *next == '\0') { 
	  dum[i]= '\0';
	  break;
	}
	dum[i]= *next;
	next++;
      }
      col = RGB_DB::XNamedColor_to_RGBcolor(dum);
    }

  switch (*buf) {
  case 'l':
    build->set_cmd_insert_line(fref,idx_zero, Line2d(Point2d(dd[0],dd[1]),Point2d(dd[2],dd[3])),0,col);
    break;
  case 'c':
    build->set_cmd_insert_circle(fref,idx_zero, Circle2d(Point2d(dd[0],dd[1]),dd[2]),0,col);
    break;
  case 'p':
    build->set_cmd_insert_point(fref,idx_zero, Point2d(dd[0],dd[1]),0,col);
    break;
  }

  if ( ! strskip(next,';',next) )
    return false;
  return true;
} 

bool SMonitorDevice::server_interpret_showinfo_t(BuilderBase * build, void *ptr) {
  static char *PlayModeString[] = PLAYMODE_STRINGS;
  SSrv::dispinfo_t *dispinfo= (SSrv::dispinfo_t*)ptr;

  if (ntohs (dispinfo->mode) != SHOW_MODE) {
    ERROR_OUT << "\nmode != SHOW_MODE";
    return false;
  }

  const SSrv::showinfo_t &showinfo= dispinfo->body.show; //shortcut
  server_state.left_teamname.set( showinfo.team[0].name);
  server_state.right_teamname.set( showinfo.team[1].name);
  //match info
  short s_l= ntohs(showinfo.team[0].score);
  short s_r= ntohs(showinfo.team[1].score);
  if ( '\0'==server_state.left_teamname.name[0] ) s_l = 0;
  if ( '\0'==server_state.right_teamname.name[0] ) s_r = 0;
	       
  char dum[30];
  char * pmstr;
  if (showinfo.pmode >= 0 && showinfo.pmode < 36)
    pmstr= PlayModeString[int(showinfo.pmode)];
  else {
    sprintf(dum,"sim_mode %d",showinfo.pmode);
    pmstr= dum;
  }
      
  sprintf(server_state.match_information.name," %10s %d:%d %-10s %16s %6d    ",
	  showinfo.team[0].name, int(s_l),int(s_r),
	  showinfo.team[1].name,
	  pmstr,
	  ntohs(showinfo.time));
    
  if ( server_state.reconnected ) {//clear the drawing plane
    DEBUG( << " refreshing drawarea");  
    build->set_cmd_empty_frame(frame_canvas_left);
    build->set_cmd_empty_frame(frame_canvas_right);
  }
	
  { //set the ball
    /* Zwischenspeicherung als short notwendig, da ansonsten ntohs nicht richtig funkioniert */
    short s_x      = ntohs(showinfo.pos[0].x);
    short s_y      = ntohs(showinfo.pos[0].y);
    Point2d pos;
    pos.x     = x_SERVER_2_LP (s_x / SHOWINFO_SCALE);
    pos.y     = y_SERVER_2_LP (s_y / SHOWINFO_SCALE);
    server_pos.set_ball_pos(pos); //just to collect informations

    if (options.active_in_mode != id_ball || options.mode != Options::MODE_MOVE )
      build->set_cmd_set_frame_pos(frame_ball,pos);
    else
      build->set_cmd_set_frame_pos_ang(frame_shadow,pos,Angle());

    if (options.track_ball)
      build->set_cmd_set_frame_pos(0,Point2d(- pos.x,-pos.y)); 
  } 

  for (int i= 0; i< 2*MAX_PLAYER; i++) { //players [0 ... MAX_PLAYER*2-1] 
    /* Zwischenspeicherung als short notwendig, da ansonsten ntohs nicht richtig funkioniert */
    short s_x      = ntohs(showinfo.pos[i+1].x);
    short s_y      = ntohs(showinfo.pos[i+1].y);
    short s_mode   = ntohs(showinfo.pos[i+1].enable);
    //short s_side   = ntohs(showinfo.pos[i+1].side);
    //short s_unum   = ntohs(showinfo.pos[i+1].unum);
    short s_angle  = ntohs(showinfo.pos[i+1].angle);
    Point2d pos;
    pos.x     = x_SERVER_2_LP (s_x / SHOWINFO_SCALE);
    pos.y     = y_SERVER_2_LP (s_y / SHOWINFO_SCALE);
    Angle angle = Angle( ang_SERVER_2_LP ( double(s_angle)) );

    server_pos.set_player(i,pos,angle); //just to collect informations

    if (options.active_in_mode != i || options.mode != Options::MODE_MOVE )
      build->set_cmd_set_frame_pos_ang(p_frame(i),pos,angle);
    else  
      build->set_cmd_set_frame_pos_ang(frame_shadow,pos,angle);

    vis_player[i].set_active(s_mode != DISABLE);
    vis_player[i].set_goalie(s_mode & GOALIE);
    vis_player[i].set_kicking(s_mode & KICK);
    vis_player[i].set_ball_collision(s_mode & BALL_COLLIDE);
  }

  server_state.reconnected= false;
  return true;
}


bool SMonitorDevice::server_interpret_drawinfo_t(BuilderBase * build, void *ptr) {
  SSrv::dispinfo_t *dispinfo= (SSrv::dispinfo_t*)ptr;
  
  short s_x, s_y, s_x2, s_y2, s_r;      
  Point2d pos, pos2;
  double r;
  bool redraw= false;
  const int idx_zero = 0;

  if (ntohs (dispinfo->mode) != DRAW_MODE) {
    ERROR_OUT << "\nmode != DRAW_MODE";
    return false;
  }

  const SSrv::drawinfo_t &drawinfo= dispinfo->body.draw; //shortcut
  switch (ntohs(drawinfo.mode)) {
  case DrawPoint:
    redraw= true;
    s_x   = ntohs(drawinfo.object.pinfo.x);
    s_y   = ntohs(drawinfo.object.pinfo.y);
    pos.x     = x_SERVER_2_LP (s_x );
    pos.y     = y_SERVER_2_LP (s_y );
    //cout << "\nDrawPoint " << draw_obj_idx << " x,y= " << x << "," << y;
    build->set_cmd_insert_point(frame_canvas_left,idx_zero,pos,0,
				RGB_DB::XNamedColor_to_RGBcolor(drawinfo.object.pinfo.color));

    break ;
  case DrawCircle:
    redraw= true;
    s_x   = ntohs(drawinfo.object.cinfo.x);
    s_y   = ntohs(drawinfo.object.cinfo.y);
    s_r   = ntohs(drawinfo.object.cinfo.r);
    r     = s_r;
    pos.x     = x_SERVER_2_LP ( s_x ) + r;
    pos.y     = y_SERVER_2_LP ( s_y ) - r;

    //cout << "\nDrawCircle " << draw_obj_idx << " (x,y),r= (" << x << "," << y << "), "<< r;
    build->set_cmd_insert_circle(frame_canvas_left,idx_zero,Circle2d(pos,r),0,
				 RGB_DB::XNamedColor_to_RGBcolor(drawinfo.object.cinfo.color));
    break ;
  case DrawLine:
    redraw= true;
    s_x   = ntohs(drawinfo.object.linfo.x1);
    s_y   = ntohs(drawinfo.object.linfo.y1);
    s_x2  = ntohs(drawinfo.object.linfo.x2);
    s_y2  = ntohs(drawinfo.object.linfo.y2);
    pos.x     = x_SERVER_2_LP (s_x  );
    pos.y     = y_SERVER_2_LP (s_y  );
    pos2.x    = x_SERVER_2_LP (s_x2 );
    pos2.y    = y_SERVER_2_LP (s_y2 );
    build->set_cmd_insert_line(frame_canvas_left,idx_zero,Line2d(pos,pos2),0,
			       RGB_DB::XNamedColor_to_RGBcolor(drawinfo.object.linfo.color));
    break ;
  case DrawClear:
    redraw= true;
    DEBUG( << " refreshing drawarea");  
    build->set_cmd_empty_frame(frame_canvas_left);
    build->set_cmd_empty_frame(frame_canvas_right);
    //field.drawclear() ;
    break ;
  default:
    ERROR_OUT << "\nIllegal value in DRAW_MODE: " << ntohs(drawinfo.mode);
  }
  return redraw;
}

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
bool SMonitorDevice::server_interpret_msginfo_t(BuilderBase * build, void *ptr) {
#if 1
  SSrv::dispinfo_t *dispinfo= (SSrv::dispinfo_t*)ptr;
#else
  SSrv::dispinfo_t2 *dispinfo= (SSrv::dispinfo_t2*)ptr; //this is correct, but doesn't function with our patched logplayer
#endif

  if (ntohs (dispinfo->mode) != MSG_MODE) {
    ERROR_OUT << "\nmode != MSG_MODE";
    return false;
  }
  //cout <<"\nMSG_MODE ";
  int canvas;

  //left player is sending on MSG_BOARD, right player is sending on LOG_BOARD
  //coordinates of right player have to be converted
  if ( ntohs(dispinfo->body.msg.board) == LOG_BOARD)
    canvas= frame_canvas_right; 
  else
    canvas= frame_canvas_left;

  const char * msg= dispinfo->body.msg.message; //shortcut
#if 0
  cout <<"\n got message, canvas= " << canvas << " msg= ";
  cout << "\n>>>";// << msg;
  for (int i=0; i< 300; i++) {
    if ( msg[i] == '\0' )
      break;
    else if ( isprint(msg[i]))
      cout << msg[i];
    else 
      cout << '@';
  }
  cout << flush;
#endif

  return server_interpret_frameview_msg(build,msg,true,canvas);
}

void SMonitorDevice::show_parser_error_point(ostream & out, const char * origin, const char * parse_error_point) {
  if (parse_error_point)
    for (  ; origin<parse_error_point && *origin!= '\0';origin++)
      out << *origin;
  else {
    out << origin
	<< "\n[no parse error point provided]";
  }
  
  if (origin != parse_error_point) {
    out << "\n[something wrong with parse error point]";
    return;
  }
  out << "   <***parse error***>   ";
  int i=0;
  while (i<25 && *origin != '\0') {
    out << *origin;
    origin++;
    i++;
  }
  if (*origin != '\0')
    out << " .......";
}


bool SMonitorDevice::server_interpret_frameview_msg(BuilderBase * build, const char * msg, bool enforce_frame, int frame) {
  int canvas;
  if ( ! strskip(msg,"_2D_",msg) ) {
    ERROR_OUT << "\nNOT recognized as 2d object" << flush;
    return false;	 
  }

  if (enforce_frame) 
    canvas= frame;
  else {
    if ( msg[0] == 'R' ) {
      canvas= frame_canvas_right;
      msg++; 
    }
    else if ( msg[0] == 'L' ) {
      canvas= frame_canvas_left;
      msg++; 
    }
    else 
      canvas= frame_canvas_left;
  }
  //cout << "\ngot 2D message " << msg << flush;

  while ( true ) { 
    strspace(msg,msg);
    if ( msg[0] == '\0' )
      break;

    const char * beg_msg= msg;
    int res= false;

    if (strncmp (msg,"CLEAR",5) == 0 ) {
      //clear drawing plane
      msg += 5;
      DEBUG( << " refreshing drawarea");  
      build->set_cmd_empty_frame(frame_canvas_left);
      build->set_cmd_empty_frame(frame_canvas_right);
      if ( strskip(msg,';',msg) )
	res= true;
    }
    else if (msg[0]== 'l' || msg[0] == 'c' || msg[0] == 'p') 
      res= ins_simple_obj(msg,canvas,build,msg);
    else 
      res= AsciiProcessor::ins_obj(msg,canvas,build,msg);
    
    if (!res) {
      ERROR_OUT << "\nDrawing input parse error:\n";
      //ERROR_STREAM << "\noriginal message: " << str;
      //ERROR_STREAM << "\n\n>>>";
      show_parser_error_point(ERROR_STREAM,beg_msg,msg);
      return false;
    }
  }
  return true;
  //cout << dispinfo.body.msg.message << flush;
}

//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
bool SMonitorDevice::server_interpret_showinfo_t2(BuilderBase * build, void *ptr) {
  static char *PlayModeString[] = PLAYMODE_STRINGS;
  SSrv::dispinfo_t2 *dispinfo= (SSrv::dispinfo_t2*)ptr;

  if (ntohs (dispinfo->mode) != SHOW_MODE) {
    ERROR_OUT << "\nmode != SHOW_MODE";
    return false;
  }

  const SSrv::showinfo_t2 &showinfo= dispinfo->body.show; //shortcut
  server_state.left_teamname.set( showinfo.team[0].name);
  server_state.right_teamname.set( showinfo.team[1].name);
  //match info
  short s_l= ntohs(showinfo.team[0].score);
  short s_r= ntohs(showinfo.team[1].score);
  if ( '\0'==server_state.left_teamname.name[0] ) s_l = 0;
  if ( '\0'==server_state.right_teamname.name[0] ) s_r = 0;
	       
  char dum[30];
  char * pmstr;
  if (showinfo.pmode >= 0 && showinfo.pmode < 36) 
    pmstr= PlayModeString[int(showinfo.pmode)];
  else {
    sprintf(dum,"sim_mode %d",showinfo.pmode);
    pmstr= dum;
  }
      
  sprintf(server_state.match_information.name," %10s %d:%d %-10s %16s %6d    ",
	  showinfo.team[0].name, int(s_l),int(s_r),
	  showinfo.team[1].name,
	  pmstr,
	  ntohs(showinfo.time));
    
  if ( server_state.reconnected ) {//clear the drawing plane
    DEBUG( << " refreshing drawarea");  
    build->set_cmd_empty_frame(frame_canvas_left);
    build->set_cmd_empty_frame(frame_canvas_right);
  }

  //set the ball
  long l_x      = ntohl(showinfo.ball.x);
  long l_y      = ntohl(showinfo.ball.y);
  //the velocity is 
  long l_vx     = ntohl(showinfo.ball.deltax);
  long l_vy     = ntohl(showinfo.ball.deltay);

  Positions::Ball & b= server_pos.ball;
  b.pos.x= x_SERVER_2_LP ( double(l_x) / SHOWINFO_SCALE2);
  b.pos.y= y_SERVER_2_LP ( double(l_y) / SHOWINFO_SCALE2);
  b.vel.x= x_SERVER_2_LP ( double(l_vx) / SHOWINFO_SCALE2);
  b.vel.y= y_SERVER_2_LP ( double(l_vy) / SHOWINFO_SCALE2);

  if (options.active_in_mode != id_ball || options.mode != Options::MODE_MOVE ) {
    build->set_cmd_set_frame_pos(frame_ball,b.pos);
    if (options.show_ball_vel) 
      vis_ball.set_show_vel(b.vel);
    vis_ball_set_info_level( options.info_level );
  }
  else
    build->set_cmd_set_frame_pos_ang(frame_shadow,b.pos,Angle());
  
  if (options.track_ball)
    build->set_cmd_set_frame_pos(0,Point2d(-b.pos.x,-b.pos.y)); 

  //set players
  for (int i= 0; i< 2*MAX_PLAYER; i++) {
    const SSrv::player_t & info_pos = showinfo.pos[i];
    /* Zwischenspeicherung als short notwendig, da ansonsten ntohs nicht richtig funkioniert */
    long l_x      = ntohl(info_pos.x);
    long l_y      = ntohl(info_pos.y);
    short s_mode  = ntohs(info_pos.mode);
    short s_type  = ntohs(info_pos.type);
    long l_body_angle  = ntohl(info_pos.body_angle);
    long l_head_angle  = ntohl(info_pos.head_angle);

    long l_stamina     = ntohl(info_pos.stamina);
    long l_view_width = ntohl(info_pos.view_width);
    short s_view_quality = ntohs(info_pos.view_quality);

    Positions::Player & p= server_pos.ref_player(i);
    VisualPlayer & vis_p= vis_player[i];

    p.pos.x     = x_SERVER_2_LP ( double(l_x) / SHOWINFO_SCALE2);
    p.pos.y     = y_SERVER_2_LP ( double(l_y) / SHOWINFO_SCALE2);

    p.type= s_type;
    //angles are now radians (but still in wrong direction) (ver. 7.00),
    p.body_angle =  - double(l_body_angle) / SHOWINFO_SCALE2;
    p.head_angle_rel =  - double(l_head_angle) / SHOWINFO_SCALE2;
    p.view_width= double(l_view_width)/ SHOWINFO_SCALE2;
    p.view_quality= s_view_quality;
    p.stamina= double(l_stamina) / SHOWINFO_SCALE2;
    p.alive= s_mode != DISABLE;

    if (options.active_in_mode != i || options.mode != Options::MODE_MOVE ) {
      build->set_cmd_set_frame_pos_ang(p_frame(i),p.pos,p.body_angle);
      vis_p.set_head_angle(p.head_angle_rel);
    }
    else
      build->set_cmd_set_frame_pos_ang(frame_shadow,p.pos,p.body_angle);

    if (options.active_in_mode == i && options.mode == Options::MODE_SHOW_VIEW_AREA ) {
      vis_view_area.set_view_mode(p.view_quality,p.view_width);
      build->set_cmd_set_frame_pos_ang(frame_varea, p.pos,p.body_angle + p.head_angle_rel);
    }

    if ( guess.use_type ) vis_p.set_type(p.type);
    vis_p.set_active( p.alive );
    vis_p.set_goalie(s_mode & GOALIE);
    vis_p.set_kicking(s_mode & KICK);
    if (options.show_ball_collisions)
      vis_p.set_ball_collision(s_mode & BALL_COLLIDE);

    if ( guess.use_stamina) vis_p.set_low_stamina_indicator( p.stamina < 1500.0);

    vis_player_set_info_level(options.info_level, vis_p, p);
  }

#if 1
  if (options.rt_show_spare_space_to_offside_line) {
    double x1, x2, x3;
    bool res= server_pos.lt_min_x_pos(x1,x2) && server_pos.rt_min_x_pos(x3);
    //cout << "\nres= " << res << " x1= " << x1 << " x2= " << x2 << "; x3= " << x3 << flush;
    if (x2>0.0)
      x2= 0.0;
    if (res && x2 < x3) {
      if (server_pos.ball.pos.x < x2)
	x2= server_pos.ball.pos.x;
      //cout << "<<<<<<<<<<< use it" << flush;
      vis_field.use_vertical_stripe(true);
      vis_field.set_vertical_stripe(x2,x3);
    }
    else
      vis_field.use_vertical_stripe(false);
  }
  else if (options.lt_show_spare_space_to_offside_line) {
    double x1, x2, x3;
    bool res= server_pos.rt_max_x_pos(x1,x2) && server_pos.lt_max_x_pos(x3);
    //cout << "\nres= " << res << " x1= " << x1 << " x2= " << x2 << "; x3= " << x3 << flush;
    if (x2<0.0)
      x2= 0.0;
    if (res && x2 > x3) {
      if (server_pos.ball.pos.x > x2)
	x2= server_pos.ball.pos.x;
      //cout << "<<<<<<<<<<< use it" << flush;
      vis_field.use_vertical_stripe(true);
      vis_field.set_vertical_stripe(x2,x3);
    }
    else
      vis_field.use_vertical_stripe(false);
  }
  else
    vis_field.use_vertical_stripe(false);  

#endif

  server_state.reconnected= false;

  return true;
}

bool SMonitorDevice::server_interpret_player_type_t(BuilderBase * build, void *ptr) {
  SSrv::dispinfo_t2 *dispinfo= (SSrv::dispinfo_t2*)ptr;

  if (ntohs (dispinfo->mode) != PT_MODE) {
    ERROR_OUT << "\nmode != PT_MODE";
    return false;
  }
  
  const SSrv::player_type_t &player_type= dispinfo->body.ptinfo; //shortcut
  if (options.list_player_types) {
    cout << ""
	 << "\ntype= " << ntohs(player_type.id)
	 << "\nplayer_speed_max= " << double(ntohl(player_type.player_speed_max)) / SHOWINFO_SCALE2
	 << "\nstamina_inc_max = " << double(ntohl(player_type.stamina_inc_max)) / SHOWINFO_SCALE2
	 << "\nplayer_decay    = " << double(ntohl(player_type.player_decay)) / SHOWINFO_SCALE2
	 << "\ninertia_moment  = " << double(ntohl(player_type.inertia_moment)) / SHOWINFO_SCALE2
	 << "\ndash_power_rate = " << double(ntohl(player_type.dash_power_rate)) / SHOWINFO_SCALE2
	 << "\nplayer_size     = " << double(ntohl(player_type.player_size)) / SHOWINFO_SCALE2
	 << "\nkickable_margin = " << double(ntohl(player_type.kickable_margin)) / SHOWINFO_SCALE2
	 << "\nkick_rand       = " << double(ntohl(player_type.kick_rand)) / SHOWINFO_SCALE2
      // << "\nextra_stamina   = " << double(ntohl(player_type.extra_stamina)) / SHOWINFO_SCALE2
      // << "\neffort_max      = " << double(ntohl(player_type.effort_max)) / SHOWINFO_SCALE2
      // << "\neffort_min      = " << double(ntohl(player_type.effort_min)) / SHOWINFO_SCALE2
	 << "";
  }

  short s_type= ntohs(player_type.id);
  double player_size= double(ntohl(player_type.player_size))/SHOWINFO_SCALE2;
  double kickable_margin= double(ntohl(player_type.kickable_margin))/SHOWINFO_SCALE2;

  static bool put_warning= false;

  if ( fabs(player_size) < 0.01 ) {
    if (!put_warning) {
      WARNING_OUT << "\nlogplayer seems not to send player types info (check for version >= 7.08)";
      PlayerTypes::use_std_type= true;
      put_warning= true;
    }
    guess.use_type= false;
    return false;
  }
  guess.use_type= true;
  guess.use_stamina= true;

  PlayerTypes::use_std_type= false;

  PlayerTypes::set_type(s_type, player_size, kickable_margin);
  return false;
}

bool SMonitorDevice::server_interpret_server_params_t(BuilderBase * build, void *ptr) {
  SSrv::dispinfo_t2 *dispinfo= (SSrv::dispinfo_t2*)ptr;

  if (ntohs (dispinfo->mode) != PARAM_MODE) {
    ERROR_OUT << "\nmode != PARAM_MODE";
    return false;
  }
  
  const SSrv::server_params_t &server_params= dispinfo->body.sparams; //shortcut

  double goal_width= double(ntohl(server_params.gwidth)) / SHOWINFO_SCALE2;
  if ( fabs(goal_width) < 0.01 ) {
    WARNING_OUT << "\nlogplayer seems not to send correct server parameters (check for version >= 7.08)";
    return false;  
  }

  vis_field.set_goal_width( double(ntohl(server_params.gwidth)) / SHOWINFO_SCALE2 );
  vis_ball.set_ball_decay( double(ntohl(server_params.bdecay)) / SHOWINFO_SCALE2 );

#if 0
  long stamina_inc ;                          /* player stamina inc */
  long visdist ;                                      /* visible distance */
  long kickable_area ;                        /* kickable_area */
  long catch_area_l ;                 /* goalie catchable area length */
  long catch_area_w ;                 /* goalie catchable area width */
  long catch_prob ;                           /* goalie catchable possibility */
  short   goalie_max_moves;                 /* goalie max moves after a catch */      
  long ckmargin ;                             /* corner kick margin */
#endif    

  return true;
}

char SMonitorDevice::p_char(int i) {
  int k= p_number(i);
  char dum;
  dum = char (k+48);
  if (k==10) dum = 'A';
  if (k==11) dum = 'B';
  return dum;
}

void SMonitorDevice::set_object_pos(BuilderBase * build, int o_id, const Point2d & pos) {
  if ( o_ball(o_id) ) {
    server_pos.set_ball_pos(pos); //just to collect informations	
    build->set_cmd_set_frame_pos(frame_ball,pos);
    return;
  }

  server_pos.set_player_pos(o_id,pos); //just to collect informations	
  build->set_cmd_set_frame_pos(p_frame(o_id),pos);

  if (!server_pos.player_alive(o_id)) {
    server_pos.set_player_alive(o_id);
    vis_player[o_id].set_active();
    vis_player[o_id].set_goalie( p_number(o_id) == 1 ); //assume goalie has number 1 in his team 
  }
}

void SMonitorDevice::set_all_objects_scale(BuilderBase * build, double scale) {
  build->set_cmd_set_frame_scale(frame_ball, scale);
  build->set_cmd_set_frame_scale(frame_shadow, scale);
  for (int i=0; i< 2*MAX_PLAYER; i++) 
    build->set_cmd_set_frame_scale(p_frame(i),scale);
}

void SMonitorDevice::send_object_pos(int o_id, const Point2d & pos) {
  const int length=200;
  static char dum_buf[length+1];
  if (o_ball(o_id)) {
    send_dispball(pos);
    return;
  }

  //strstream dum_str(dum_buf,100);
#if 0 // #if USE_COACH for server version < 7.02
  dum_str << "(move (player ";
  if ( p_left(o_id) )
    dum_str << server_state.left_teamname.name;
  else 
    dum_str << server_state.right_teamname.name;
  dum_str << " " << p_number(o_id) << ") " << int(pos.x) << " " <<  int(-pos.y) << ")";
  coach.send_msg(dum_str.str(),dum_str.pcount());
#else 
  /* don't use the coach to position players but the
     (dispplayer ...) command (works in server 7.02 upwards) */
  //dum_str << "(dispplayer";
  int side;
  if ( p_left(o_id) )
    side= 1;
  else 
    side= -1;

  //preserve the angle of the player
  int tmp= int(-(server_pos.player[o_id].body_angle.get_value()- 2*M_PI) * 180.0/M_PI);
  if (tmp > 180)
    tmp-= 360;
  //cout << "\n body agnle = " << int (tmp) << flush; //don't change angle 

  int len= snprintf(dum_buf,length,"(dispplayer %d %d %d %d 0 0 %d)",
      side, p_number(o_id), int(pos.x * SHOWINFO_SCALE),
      int(-pos.y * SHOWINFO_SCALE), tmp);
  server.send_msg(dum_buf,len+1);
#endif
}

void SMonitorDevice::send_dispinit() {
  if (options.protocol_version >= 2) {
    const char msg[]= "(dispinit version 2)";
    server.send_msg(msg,strlen(msg)+1);
  }
  else {
    const char msg[]= "(dispinit)";
    server.send_msg(msg,strlen(msg)+1);
    //cout << "\ntime=" << TOOLS::get_current_ms_time() << ", sending msg=:" << msg << flush;
  }
}

void SMonitorDevice::send_dispstart() {
  const char msg[]= "(dispstart)";
  server.send_msg(msg,strlen(msg)+1);
}

void SMonitorDevice::send_dispball(const Point2d & pos) {
  static char buf[100];
  sprintf(buf,"(dispfoul %d %d 0)",int(pos.x * SHOWINFO_SCALE),int( - pos.y * SHOWINFO_SCALE));
  server.send_msg(buf,strlen(buf)+1);
}

void SMonitorDevice::send_dispfoul_left(const Point2d & pos) {
  static char buf[100];
  sprintf(buf,"(dispfoul %d %d 1)",int(pos.x * SHOWINFO_SCALE),int( - pos.y * SHOWINFO_SCALE));
  server.send_msg(buf,strlen(buf)+1);
}

void SMonitorDevice::send_dispfoul_right(const Point2d & pos) {
  static char buf[100];
  sprintf(buf,"(dispfoul %d %d -1)",int(pos.x * SHOWINFO_SCALE),int( - pos.y * SHOWINFO_SCALE));
  server.send_msg(buf,strlen(buf)+1);
}

void SMonitorDevice::send_dispbye () {
  const char msg[]= "(dispbye)";
  server.send_msg(msg,strlen(msg)+1);
}

    /*
     if (false && i == 0)
      cout << "\nl_body_angle= " << l_body_angle
	   << ", res= " << double(l_body_angle) / SHOWINFO_SCALE2
	   << ", res2= " << ang_SERVER_2_LP ( double(l_body_angle) / SHOWINFO_SCALE2) 
	   << "\nl_head_angle= " << l_head_angle
	   << ", res= " << double(l_head_angle) / SHOWINFO_SCALE2
	   << ", res2= " << ang_SERVER_2_LP ( double(l_head_angle) / SHOWINFO_SCALE2) << flush;
   
    if (false && i == 0) {
      cout << "\n-- time (" << ntohs(showinfo.time) << ")"
	   << "\ntype= " << ntohs(showinfo.pos[i].type)
	   << "\nstamina= " << double(ntohl(showinfo.pos[i].stamina)) /SHOWINFO_SCALE2
	   << "\neffort= " << double(ntohl(showinfo.pos[i].effort)) / SHOWINFO_SCALE2
	   << "\nrecovery= " << double(ntohl(showinfo.pos[i].recovery)) / SHOWINFO_SCALE2
	   << "\nk= " << ntohs(showinfo.pos[i].kick_count) 
	   << " , d= " << ntohs(showinfo.pos[i].dash_count) 
	   << " , t= " << ntohs(showinfo.pos[i].turn_count) 
	   << " , m= " << ntohs(showinfo.pos[i].move_count) 
	   << " ; c= " << ntohs(showinfo.pos[i].catch_count) 
	   << " | n= " << ntohs(showinfo.pos[i].tneck_count) 
	   << " | s= " << ntohs(showinfo.pos[i].say_count) 
	   << " | v= " << ntohs(showinfo.pos[i].chg_view_count);
    }
    */
